poj 1664 放苹果(dfs/dp/母函数)

本文探讨了将M个相同的苹果分配到N个相同盘子中的不同方法数量的问题,并提供了三种解决方案:深度优先搜索(DFS)、动态规划(DP)及母函数方法。通过对每种方法的代码实现与解释,帮助读者理解并掌握此类组合计数问题。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题目:http://poj.org/problem?id=1664

Description

把M个同样的苹果放在N个同样的盘子里,允许有的盘子空着不放,问共有多少种不同的分法?(用K表示)5,1,1和1,5,1 是同一种分法。

Input

第一行是测试数据的数目t(0 <= t <= 20)。以下每行均包含二个整数M和N,以空格分开。1<=M,N<=10。

Output

对输入的每组数据M和N,用一行输出相应的K。

Sample Input

1
7 3

Sample Output

8
dfs:每回递归判断重复太傻了,可以有规律的找,每次让后面的比前面的大即可。

//#include<bits/stdc++.h>
#include<iostream>
using namespace std;

int dfs(int m,int n,int pre){
    int cnt=0;  //开始写错了,应该是数第一次循环返回的个数
    if(n==1)
        return 1;
    for(int i=pre;i<=m/n;i++){
        cnt+=dfs(m-i,n-1,i);
    }
    return cnt;
}
int main(){
    int t,m,n;
    cin>>t;
    while(t--){
        cin>>m>>n;
        cout<<dfs(m,n,0)<<endl;
    }
    return 0;
}

dp:dp[i][j]为n个盘子放m个苹果,可以拆为:4个苹果放6个盘子相当于4个盘子放4个苹果dp[i][j]=dp[j][j],

 6个苹果放4个盘子相当于6个苹果放3个盘子,加上每个盘子都放了一个再放2个,就是2个苹果放4个盘子。

#include<bits/stdc++.h>
using namespace std;
int dp[15][15];

int main(){
    int n,m,t;
    fill(dp[0],dp[0]+15*15,1);
    for(int i=2;i<15;i++)
        for(int j=2;j<15;j++)
            if(i>j)
                dp[i][j]=dp[j][j];
            else
                dp[i][j]=dp[i-1][j]+dp[i][j-i];
    cin>>t;
    while(t--){
        cin>>m>>n;
        cout<<dp[n][m]<<endl;//n个盘子放m个苹果
    }
    return 0;
}

母函数:

和楼梯问题(砝码称重)的例子不同,这里和贴邮票类似,有无穷多个数可用,但做法和01背包变多重背包相似,

多加一个k循环即可。

#include<iostream>
using namespace std;
int c1[105],c2[105];

int main(){
    int t,n,m;
    cin>>t;
    while(t--){
        cin>>n>>m; //n分为m份
        for(int i=0;i<=n;i++){
            c1[i]=1;
            c2[i]=0;
        }
        for(int i=2;i<=m;i++){  //表示第i个括号(表达式)
            for(int j=0;j<=n;j++)  //更新系数,指数为j+k时的系数
                for(int k=0;k+j<=n;k+=i)  //i=2时,好几个(1+x^2)往里加
                    c2[j+k]+=c1[j];
            for(int j=0;j<=n;j++){
                c1[j]=c2[j];
                c2[j]=0;
            }
        }
        cout<<c1[n]<<endl;
    }
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值