POJ 1664 放苹果(DFS)
http://poj.org/problem?id=1664
题意:
把M个同样的苹果放在N个同样的盘子里,允许有的盘子空着不放,问共有多少种不同的分法?(用K表示)5,1,1和1,5,1 是同一种分法。
分析:
注意到盘子是一样的,方法5 1 1 和1 5 1 只能算一种.所以我们需要给每个盘子放的苹果数定序.
也就是说我们从少往多放,即我们从1号盘子开始放,我们可以放0-M个苹果,但是我们要保证2号盘子中放的苹果数>=1号盘子中放的苹果数,3号,4号,…N号盘子也一样.
但是这样的话,可能放到后面我们就没有苹果放了,这样违反了我们苹果从少往多放的原则,所以我们打算把苹果从多往少放.即如果我1号盘子里放了4个苹果,那么2号到N号盘子的苹果数只能<=4了.
在源代码的dfs中由下面这句:
else for(int i = min(num, left);i >= (left-1)/(n-cnt)+1; i--)
其中i表示当前盘子将要放的苹果数,既然上一个盘子放了num个苹果,i肯定要<=num了,且剩余left个苹果,所以i初值= min(num, left) 表示i能取到的最大值。
但是i能取的最小值是多少呢?i能直接取0吗?如果left>0的话,i不能取0。因为如果这个i取0,后面的盘子都得为0,当前剩余的left个苹果就没地方放了。left不为0时,i能取的最少值为:上取整(剩余苹果数/剩余盘子数)也就是(left-1)/(n-cnt)+1。注意这里要求left>=1。
如果left为0的话,i只能取0。
AC代码:
#include<cstdio>
#include<algorithm>
using namespace std;
int m,n;
int ans;//最终解
void dfs(int cnt,int left,int num)//当前已放cnt个盘子,还剩left个苹果且上把放了num个苹果,从多往少放
{
if(cnt==n&&left==0) ans++;
else if(left==0) ans++;
else for(int i = min(num, left); i >= (left-1)/(n-cnt)+1; i--)//left>0时
dfs(cnt+1,left-i,i);
}
int main()
{
int T; scanf("%d",&T);
while(T--)
{
scanf("%d%d",&m,&n);
ans=0;
dfs(0,m,100000);
printf("%d\n",ans);
}
return 0;
}