首页 > 试题广场 >

放苹果

[编程题]放苹果
  • 热度指数:12131 时间限制:C/C++ 1秒,其他语言2秒 空间限制:C/C++ 64M,其他语言128M
  • 算法知识视频讲解
把M个同样的苹果放在N个同样的盘子里,允许有的盘子空着不放,问共有多少种不同的分法?(用K表示)5,1,1和1,5,1 是同一种分法。

输入描述:
每行均包含二个整数M和N,以空格分开。1<=M,N<=10。


输出描述:
对输入的每组数据M和N,用一行输出相应的K。
示例1

输入

7 3

输出

8
#include<iostream>
using namespace std;

int M,N;
int count;
int book[20];

void DFS(int sum,int n,int u)
{
    if(sum >= M)
    {
        if(sum == M && n <= N) count++;
        return;
    }
    for(int i = u;i <= M;i++)
    {
        DFS(sum + i,n + 1,i);
    }
}

int main()
{
    cin >> M >> N;
    count = 0;
    t_ = 0;
    DFS(0,0,1);
    cout << count << endl;
    return 0;
}

发表于 2021-02-09 12:11:50 回复(0)
#include <iostream>
#include <algorithm>
using namespace std;
int main(){
    int k[11][11],m,n;
    fill(k[0],k[0]+121,1);
    for(m=2;m<=10;++m)
        for(n=2;n<=10;++n)
            k[m][n]=k[m][n-1]+(m>=n?k[m-n][n]:0);
    while (cin >> m>>n)
        cout << k[m][n] << endl;
    return 0;
}

发表于 2021-01-27 06:46:20 回复(0)
可用DFS做。
#include<cstdio>
using namespace std;
int M,N;
int cnt;
int t=0;
void DFS(int pre,int num,int d){
    if(d>N+1)return;
    if(d==N+1){
        if(num==0)cnt++;
        else return;
    }
    if(pre*(N-d+1)<num)return;
    for(int i=0;i<=num;i++){
        if(i>pre)break;
        printf("d=%d i=%d\n",d,i);t++;
        DFS(i,num-i,d+1);
    }
}
int main(){
    while(scanf("%d%d",&M,&N)!=EOF){
        cnt=0;
        DFS(M+1,M,1);
        printf("%d\n",cnt);
    }
}


编辑于 2019-09-06 15:42:40 回复(0)
while True:
    try:
        m,n = list(map(int,input().split()))
        dp = [[0 for i in range(n+1)] for j in range(m+1)] #dp[i][j]表示j个盘子装i个苹果
        for i in range(1,m+1):
            dp[i][1] = 1
            for j in range(2,n+1):
                if i < j:                    #盘子比苹果多并不会增加分法
                    dp[i][j] = dp[i][j-1]
                elif i == j:                 #盘子和苹果一样多,相当于多了一个全部盘子只摆一个,其他摆法起码有一个空盘
                    dp[i][j] = dp[i][j-1] + 1
                else:                        #盒子比苹果少,等于有一个空盘加上全部盘摆上一个苹果剩余的摆法
                    dp[i][j] = dp[i-j][j] + dp[i][j-1]
        print(dp[m][n])
    except Exception:
        break
编辑于 2018-10-08 18:29:26 回复(0)
#include<iostream>
using namespace std;

int C(int n,int m)
{
    if(m>n)return C(n,n);
    if(n<=1||m<=1) return 1;
    else return C(n,m-1)+C(n-m,m);  
}

int main()
{
    int n,m;
    cin>>n>>m;
    int sum;
    sum=C(n,m);
    cout<<sum<<endl;
    return 0;
}
发表于 2018-02-18 15:26:05 回复(0)

python DP  7行解法:

for _ in range(int(input())):
    a, b = map(int, input().split())
    dp = [[1 for i in range(b + 1)] for j in range(a + 1)]
    for i in range(1, a + 1):
        for j in range(2, b + 1):
            dp[i][j] = (dp[i][j - 1] + dp[i - j][j]) if i >= j else dp[i][j - 1]
    print(dp[-1][-1])
编辑于 2017-10-23 15:29:15 回复(0)
设dp(m,n) 为m个苹果,n个盘子的放法数目,则先对n作讨论,
        当n>m:必定有n-m个盘子永远空着,去掉它们对摆放苹果方法数目不产生影响。即if(n>m) dp(m,n) = dp(m,m)
        当n<=m:不同的放法可以分成两类:
        1、有至少一个盘子空着,即相当于f(m,n) = f(m,n-1);  
        2、所有盘子都有苹果,相当于可以从每个盘子中拿掉一个苹果,不影响不同放法的数目,即dp(m,n) = dp(m-n,n).
        而总的放苹果的放法数目等于两者的和,即 f(m,n) =f(m,n-1)+f(m-n,n) 


import java.util.Scanner;

/*
 * 设dp(m,n) 为m个苹果,n个盘子的放法数目,则先对n作讨论,
        当n>m:必定有n-m个盘子永远空着,去掉它们对摆放苹果方法数目不产生影响。即if(n>m) dp(m,n) = dp(m,m)
        当n<=m:不同的放法可以分成两类:
        1、有至少一个盘子空着,即相当于f(m,n) = f(m,n-1);  
        2、所有盘子都有苹果,相当于可以从每个盘子中拿掉一个苹果,不影响不同放法的数目,即dp(m,n) = dp(m-n,n).
        而总的放苹果的放法数目等于两者的和,即 f(m,n) =f(m,n-1)+f(m-n,n) 

 递归出口条件说明:
        当n=1时,所有苹果都必须放在一个盘子里,所以返回1;
        当没有苹果可放时,定义为1种放法;
        递归的两条路,第一条n会逐渐减少,终会到达出口n==1; 
        第二条m会逐渐减少,因为n>m时,我们会return f(m,m) 所以终会到达出口m==0.
 * 
 * 
 * 
 * */
public class Main {

public static void main(String[] args) {
// TODO Auto-generated method stub
Scanner in = new Scanner(System.in);
while (in.hasNext()) {
int cnt = in.nextInt();
for (int i = 0; i < cnt; i++) {
int M = in.nextInt();
int N = in.nextInt();
System.out.println(processdp(M, N));
}
}
in.close();
}

private static int processPutApple(int m, int n) {
// TODO Auto-generated method stub
if (m == 0 || n == 1)
return 1;
if (n > m)
return processPutApple(m, m);
else
return processPutApple(m, n - 1) + processPutApple(m - n, n);
}

static int processdp(int m, int n) {
int[][] dp = new int[m + 1][n + 1];//m个苹果放进n个盘子的最大值
for (int i = 0; i <= m; i++) {
dp[i][1] = 1; //m个苹果放进一个盘子 1种方法
}
for (int i = 0; i <= n; i++) {
dp[0][i] = 1; //0个苹果放进n个盘子 1种方法
}
for (int i = 1; i <= m; i++) {
for (int j =1; j <= n; j++) {
if (j <= i)//苹果比盘子多的情况下
dp[i][j] = dp[i][j - 1] + dp[i - j][j];
else //盘子多,苹果少 必然有空盘子
dp[i][j] = dp[i][i];
}
}
return dp[m][n];
}
}

发表于 2016-07-21 15:10:46 回复(5)
/*
    M个苹果放在N个盘子里分法有:dp[M][N], 0 <= M,N <= 10
    设dp(m,n) 为m个苹果,n个盘子的放法数目,则先对n作讨论,
    当m<n:必定有n-m个盘子永远空着,去掉它们对摆放苹果方法数目不产生影响。dp(m,n) = dp(m,m)
    当m>=n:不同的放法可以分成两类:
        1、有至少一个盘子空着,即相当于dp(m,n) = dp(m,n-1);
        2、所有盘子都有苹果,相当于可以从每个盘子中拿掉一个苹果,不影响不同放法的数目,即dp(m,n) = dp(m-n,n).
        而总的放苹果的放法数目等于两者的和,即 dp(m,n) =dp(m,n-1)+dp(m-n,n)
    初始条件说明
        当m=0,n=0时,没苹果,没盘子,定为0种放法。这个条件在计算的时候用不到。题设至少一个盘子一个苹果。
        当m=0,n>0时,没苹果,有盘子,定为1种放法。这个有点抽象,考虑:dp[1][1]=dp[1][0]+dp[0][1]=0+1。
        当m>0,n=0时,有苹果,没盘子,定为0种放法。
        dp两条路,第一条n会逐渐减少,终会到达出口n=0;
        第二条m会逐渐减少,因为n>m时,会计算dp(m,m) 所以终会到达出口m=0.
*/

#include <stdio.h>
#if US_DP
int dp[11][11];

int main()
{
    int m, n;

    while (scanf("%d%d", &m, &n) != EOF) {
        for (int i = 1; i <= m; ++i)
            dp[i][0] = 0;
        for (int j = 1; j <= n; ++j)
            dp[0][j] = 1;

        for (int i = 1; i <= m; ++i) {
            for (int j = 1; j <= n; ++j) {
                if (i >= j)
                    dp[i][j] = dp[i][j-1]+dp[i-j][j];
                else
                    dp[i][j] = dp[i][i];
            }
        }
        printf("%d\n", dp[m][n]);
    }

    return 0;
}

#else

int f(int m, int n)
{
    if (m >= 0 && n == 0)
        return 0;
    else if (m == 0 && n > 0)
        return 1;
    else if (m >= n)
        return f(m, n-1)+f(m-n, n);
    else
        return f(m, m);
}

int main()
{
    int m, n;

    while (scanf("%d%d", &m, &n) != EOF)
        printf("%d\n", f(m, n));
}
#endif

发表于 2019-01-29 10:25:14 回复(5)
#include<iostream>
#include<cstdio>
using namespace std;

// 求解
int solve(int m, int n)
{
    if(m == 0)
        return 1;       // 没有剩余了则 +1
    if(n == 1)
        return 1;       // 只有1个箱子了则 +1
    if(m < n)
        return solve(m, m);     // 如果 m < n 则最多放到 m 个箱子中
    else
        return solve(m, n-1) + solve(m-n, n);       // m , n 等于 1.至少一个箱子空着 + 2.所有盘子都有至少一个苹果,则等价于都拿掉1个

}

int main()
{
    int t;
    int m, n;
    while(cin >> t)
    {
        while(t--)
        {
            cin >> m >> n;
            // begin
            cout << solve(m, n) << endl;
            // end
        }
    }

    return 0;
}


发表于 2016-08-09 11:14:05 回复(4)
#include<stdio.h>
#include<string.h>
int dp[105][105][105];
int main(){
	int N,M,i,j,T,k;
	//freopen("input.txt","r",stdin);
	for(scanf("%d",&T);T--;){
		memset(dp,0,sizeof(dp));
		scanf("%d%d",&M,&N);
		for(k=1;k<=N;k++)
			for(i=0;i<=M;i++) 
				for(j=0;j<=i;j++)
					dp[k][i][j]=1;
		for(k=2;k<=N;k++)
			for(i=1;i<=M;i++)
				for(j=1;j<=M;j++){
					dp[k][i][j]=dp[k][i-1][j];
					if(j>=i) dp[k][i][j]+=dp[k-1][i][j-i];
				}
		printf("%d\n",dp[N][M][M]);
	}
}//把问题转化为:在 0...M 中 , 只取 N 个数 , 使得他们的和为M的情况有多少种
// 那么 dp[k][i][j]的意义就是 在0到i中 取k个数  使得和为j的情况数

编辑于 2017-08-05 18:33:56 回复(2)
动态规划问题。高赞的“菜鸟葫芦娃”分析的很透彻了,我就不多bb了
#include <stdio.h>

int dp(int m, int n)
{
    if(n==1) return 1;
    else if(m==0) return 1;
    else if(n>m) return dp(m, m);
    else return dp(m, n-1)+dp(m-n, n);
}

int main()
{
    int m, n;
    while(scanf("%d %d", &m, &n)!=EOF)
    {
        printf("%d\n", dp(m, n));
    }
    return 0;
}

发表于 2018-02-22 09:01:13 回复(2)
/*
    装苹果,一个完全背包的问题
    状态表示:f[i][j] 表示只用前i个盘子放j个苹果的所有方法
            属性:选法的数量和
    状态计算:
	第i个盘子放多少个,可以放0,1,2,3,4....j-i;个
	f[i][j] = f[i-1][j]+ f[i-1][j-1] + f[i-1][j-2] + .......+f[i-1][j-i];
	
	f[i][j-1] =        + f[i-1][j-1] + f[i-1][j-2] + f[i-1][j-2] +......+f[i-1][j-i];
	
    那么f[i][j] = f[i-1][j] + f[i][j-1];
*/

#include <bits/stdc++.h>
using namespace std;
const int maxn = 25;
int f[maxn];
int main() {
	int n,m; // n是盘子,m是苹果数量
	while(cin>>m>>n) {
		f[0] = 1;
		for(int i=1;i<=m;i++) f[i] = 0; // 初始化
		for(int i=1; i<=n; i++) { // 遍历盘子
			for(int j=i; j<=m; j++) { // 从i到m放苹果
				f[j] = f[j] + f[j-i];
			}
		}
		cout<<f[m]<<endl;
	}
}

发表于 2020-03-26 19:39:12 回复(2)
递归解法
/**
*这是一个递推数列,只要是递推数列,找到递推公式
*就可以用递归来做
*以f(m,n)表示数列中的项
*①m < n
*    m < n时必有盘子是空的,只需要找到一对m1,n1,满足m1 = m,n1 <= n,且f(m1,n1) = f(m,n)即可
*    那么我们可以发现当n1取m到n这段数字之间的任何数字都是可以的。
*②m >= n 
* 关键:这一部分的递推公式是根据含有至少一个空盘子的集合和不含空盘子的集合之间的转化得来的
*     
* 分两种情况讨论:
*  记g(m,n)表示m个苹果放在n个盘子里的放法集合中含有至少一个空盘子的子集中元素的数量
*    h(m,n)表示不含空盘子的情况
* (1)含空盘子的集合,g(m,n) = f(m,n-1)
* (2)不含空盘子的递推公式,h(m,n) = f(m-n,n),因为在m-n个苹果,放在n个盘子里的情况下,
*     往每个盘子里放一个苹果,就得到了m个苹果放入n个盘子的情况,则h(m,n) >= f(m-n,n)
*     在h(m,n)的所有放法中,从每个盘子里拿去一个苹果,就到了在m-n个苹果,放在n个盘子里的情况
*     所以h(m,n)<=f(m-n,n)
*递归的出口:
*m == 0 || n == 1
*分别表示0个苹果放一个n个盘子,放法有一种
*只有一个盘子,放法也只有一种
*
*这道题和整数的划分那题有点类似
*整数的划分是根据集合中是否含有1来分类,
*它是要通过含有1的集合和不含有1的集合的转换来确定f(2m)的递推公式
*
*/
#include "stdio.h"
int f(int m, int n){
    if((m == 0) || (n== 1)) return 1;
    if(m < n) return f(m,n-1);
    else return f(m, n-1)+f(m-n,n);
}
int main(){
    int m,n;
    while(scanf("%d%d",&m, &n) != EOF){
        printf("%d\n",f(m,n));
    }
    return 0;
}
发表于 2019-06-26 18:18:54 回复(0)
import java.util.Scanner;
public class Main{
    public static void main(String[] args){
        Scanner in = new Scanner(System.in);
        while(in.hasNext()){
            int M = in.nextInt();
            int N = in.nextInt();
            System.out.println(appleCnt(M,N));
        }
    }
    public static int appleCnt(int M, int N){
        if(M==0||N==1) return 1;
        if(M<N) return appleCnt(M,M);
        else return appleCnt(M,N-1) + appleCnt(M-N,N);
    }
}

发表于 2018-03-08 15:39:24 回复(0)
#include <iostream>
using namespace std;

int f(int m,int n){
    if(n>m) n = m ;
    if(m==1||m==0||n==1) return 1;
    return f(m, n-1) + f(m-n, n);
}

int main() {
    int m,n;
    while (cin >> m >> n) {
        cout << f(m,n) << endl;
    }
    return 0;
}
编辑于 2024-03-21 16:38:22 回复(0)
本地运行没问题,不理解为啥系统无法编译。
#include <iostream>
using namespace std;

int dfs(int m, int n) {
	if (n == 1) return 1;
	if (m == 0) return 1;
	if (m < n) return dfs(m, m);
	if (m >= n) return dfs(m - n, n) + dfs(m, n - 1);
	//不留空盘子,假设每个盘子放一个;留空盘子,假设留一个空盘子;
}

int main() {
	int m, n;
	while (cin >> m >> n) {
		cout << dfs(m, n);
	}
}

编辑于 2024-03-12 20:41:53 回复(1)
//描述
//把M个同样的苹果放在N个同样的盘子里,允许有的盘子空着不放,问共有多少种不同的分法?(用K表示)5,1,1和1,5,1 是同一种分法。
//输入描述:
//每行均包含二个整数M和N,以空格分开。1<=M,N<=10。
//输出描述:
//对输入的每组数据M和N,用一行输出相应的K。
#include <iostream>
#include <string>
#include <algorithm>
using namespace std;
// 定义一个函数,用于计算m个苹果放在n个盘子中的方法数
int ways(int m,int n){
    // 当m为0时,说明没有苹果,只有空盘子,所以只有一种摆放方式:一个空盘子
    if (m==0) return 1;
    if (n==0) return 0;// 当n为0时,说明没有盘子,所以没有摆放方式
    /* 当m小于n时,那么就直接返回将m个苹果放在m个盘子中的方法数。即ways(m, m)。*/
    if (m<n){
        return ways(m,m);
    }
    /*分的方案包含两种,一是方案中不含有空的情况,则从每个盘子里面拿出一个来也不影响最终的结果,
     * 即ways(m,n) = ways(m-n,n),
     * 二是方案中含有的空的情况,至于含有几个空暂时不考虑,只用考虑一个空的就行,
     * 即ways(m,n) = ways(m,n-1),在这种递归调用中会重复调用含有空的情况,也就是最终包含了各种可能为空的情况。*/
    else{
        return ways(m,n-1)+ways(m-n,n);
    }
}
int main() {
    // 定义两个整数变量M和N,用于存储苹果和盘子的数量
    int M,N;
    while(cin>>M>>N){
        cout<<ways(M,N)<<endl;
    }
    return 0;
}

发表于 2024-01-23 10:32:09 回复(0)
#include<cstdio>
int f(int m,int n){
    if(m==0)
        return 1;
    if(n==1)
        return 1;
    if(m<n){
        return f(m,m);
    }else
        return f(m-n,n)+f(m,n-1);
}
int main(){
    int m,n;
    int q;
    scanf("%d %d",&m,&n);
    printf("%d\n",f(m,n));
    return 0;
}

发表于 2020-04-12 18:23:17 回复(0)
#include<stdio.h>
#include<string.h>
int main(){
    int M,N;
    scanf("%d%d",&M,&N);
    int dp[M+1][N+1];   //M个苹果放入N个盘子中
    memset(dp,0,(M+1)*(N+1));
    for(int i=0;i<=N;i++){
        dp[0][i]=1;   //0个苹果放入i个盘子
        dp[1][i]=1;  //1个苹果放入i个盘子
    }
    for(int j=0;j<=M;j++){
        dp[j][0] =1; //j个苹果没盘子放
        dp[j][1]=1; //j个苹果放在一个盘子里
    }
    //开始递推
    for(int i=2;i<=M;i++){
        for(int j=2;j<=N;j++){
            if(i>=j){  //i个苹果放在j个盘子中   苹果比盘子多
                dp[i][j] = dp[i][j-1]+dp[i-j][j];
            }else{  //盘子比苹果多
                dp[i][j] = dp[i][i];
            }
        }
    }

    printf("%d\n",dp[M][N]);
}

编辑于 2024-03-13 19:39:33 回复(0)
def distribute_apples(M, N):
    """
    将M个苹果分配到N个盘子的分法数,修正了M < N的情况
    """
    # 创建一个二维列表,用于存储中间结果,以减少重复计算
    dp = [[-1 for _ in range(N + 1)] for _ in range(M + 1)]

    def helper(M, N):
        # 边界条件处理
        if M < 0:
            return 0
        if M == 0&nbs***bsp;N == 1:
            return 1
        if M < N:
            return helper(M, M)  # 当苹果数少于盘子数时,直接使用苹果数作为盘子数进行计算

        # 如果这个结果已经计算过了,直接返回
        if dp[M][N] != -1:
            return dp[M][N]

        # 递归计算
        dp[M][N] = helper(M, N - 1) + helper(M - N, N)
        return dp[M][N]

    return helper(M, N)


M, N = map(int, input().split())
print(distribute_apples(M, N)) 

发表于 2024-03-10 12:20:00 回复(0)