您的位置:首页 > 移动开发

2013寒假练习 1008:Putting Apples

2013-02-01 23:22 399 查看
地址:http://acm.bit.edu.cn/mod/programming/view.php?a=494

DP好题。将n个苹果分入k的盘子,盘子可以空着,问不同的方法总数(1,2,2和2,1,2算一种)

建立dp[a][b],表示将a个苹果分入b个盘子的方法总数。初始条件为dp[a][0](0<a<101)=0,dp[0][a]](0<a<101)=1(很科学,将a个苹果分入0个盘子——不行,0种,将0个苹果分入a个盘子——全不放,1种)。那么状态转移方程是?

我们将dp[a][b]的这些方法分成两种。一种是含0的,即有盘子没放苹果的情况。这一部分情况与dp[a][b-1]的所有情况一一对应。另一种是所有盘子都至少装一个的情况,这一部分情况与dp[a-b][b]的所有情况一一对应,对应方法是每个盘子都差一个。故dp[a][b] = dp[a][b-1] + dp[a-b][b] (a>=b)及dp[a][b] = dp[a][b-1] (a<b)。

这样说可能还不好理解,我们拿实例来看:如样例 dp[7][3]=8 ,这八种方法分别是(1,1,5)(1,2,4)(1,3,3)(2,2,3)(0,1,6)(0,2,5)(0,3,4)(0,0,7)其中(1,1,5)(1,2,4)(1,3,3)(2,2,3)这四种属于第二类情况,与dp[7-3][4]的四种情况一一对应,即(0,0,4)(0,1,3)(0,2,2),(1,1,2),可以看到,对应关系为-1,-1,-1每个篮子都少一个;(0,1,6),(0,2,5),(0,3,4)(0,0,7)这四种都属于第一类情况,与dp[7][3-1]的四种情况一一对应即(1,6),(2,5),(3,4),(0,7),可以看到,对应关系为少了一个空盘子。因此dp[7][3]=dp[4][3]+dp[7][2]=8.当然,dp[4][3]和dp[7][2]也可以继续状态转移,故可以DP求解。

注意到状态转移方程要求的是上一行和这一行的前面的状态,故二重循环行嵌套列可以将dp数组求出。

(神方法啊,谁想出来的。。)

#include<iostream>
using namespace std;
int dp[101][101];
int main()
{
int i,j,n,k;
for(i=0;i<101;i++)               //初始条件
{
dp[i][0]=0,dp[0][i]=1;
}
for(i=1;i<101;i++)
{
for(j=1;j<101;j++)
{
if(i>=j) dp[i][j]=dp[i-j][j]+dp[i][j-1];    //状态转移方程
else   dp[i][j]=dp[i][j-1];
}
}
while(scanf("%d%d",&n,&k)!=EOF)
{
printf("%d\n",dp
[k]);
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: