刷题向》DP》放苹果 (normal)

这篇博客可能字数比较多,而且很难讲清楚,我会努力给你们讲清楚;

首先,放苹果是一道DP,之所以难,是因为很难想到,我的确有同学用三维数组做出来,然而三维的的确比二维好理解,但三维复杂度太高,虽然DP一般数据都给的不大,但复杂度低的算法才是好算法,所以接下来我会给讲一个二维的放苹果的思路;

首先,我们用f[i][j]来代表i个苹果放在j个盘子里,然后就可以推知当i=1或i=0或j=1时f[i][j]=1;

当然,这是必然的;

那么对于复杂的f[i][j]我们可以推知:当盘子数大于苹果数的时候,一定是有盘子装不满的,所以,f[i][j]=f[i][i];

 对于苹果数大于盘子数的情况,我们可以考虑f[i][j]从两种情况转移来,一种是有空盘子的情况,另一种是没有空盘子的情况,题目要求是要考虑两种情况,所以f[i][j]只要从两种情况转移过来就好,那么,动态规划的基本思想就是:从当前算过的情况转移过来,所以我们要把对于当前f[i][j]的有空盘子情况用算过的f[i][j]来表示,同理,我们也要用算过的f[i][j]来表示没有空盘子的情况;

由于程序里我的f[i][j]中的i和j是递增来算的,所以,在我们算f[i][j]时,对于f数组的横纵坐标小于当前i,j的情况我们是已经算过的;

所以我们考虑,对于苹果数大于盘子数的f[i][j],没有空盘子就是每个盘子至少有一个苹果的情况,那么每个盘子都有一个苹果,也就是说这些苹果不参与移动,所以我们便可以从f[i-j][j]的情况转移过来,因为对于当前情况,f[i-j][j]是算过的,代表在j个盘子里,只有i-j个苹果可以移动,这就是没有空位的情况;

那么,对于有空盘子的情况,我们可以直接从f[i][j-1]转移过来,原因很简单,因为对于f[i][j-1]来说,我们也考虑过f[i][j-2]的情况,f[i][j-2]是对于f[i][j-1]的空一个盘子的情况,也是对于f[i][j]的空两个的情况,由此递推下去,我们可以的得到空1到空j-1的个盘子的情况,当j==1时,我们就可以得到1,那么一层一层递推上来,就可以得到f[i][j-1];

最后一步,我们只需要把f[i][j-1]+f[i-j][j]就可以得到f[i][j];

以下是附加程序//我觉得我已经讲得够清楚了,应该不用看代码就可以自己写出来

ps1:以上文字还没看懂的去面壁好吗

PS2:这是我在noi.openjudge.cn里A的程序

 1 #include<stdio.h>
 2 int T,f[12][12],n,m;
 3 int main()
 4 {
 5     scanf("%d",&T);
 6     for(int i=1;i<=11;i++)
 7     f[1][i]=1;
 8     for(int i=1;i<=11;i++)
 9     {f[1][i]=1;f[0][i]=1;}
10     for(int i=1;i<=11;i++)
11     {f[i][1]=1;f[i][0]=1;}
12     for(int i=2;i<=11;i++)
13         for(int j=2;j<=11;j++)
14             {
15                 if(i>=j)f[i][j]=f[i][j-1]+f[i-j][j];
16                 else f[i][j]=f[i][i];
17             }
18     while(T--)
19     {
20         scanf("%d%d",&m,&n);//苹果M,盘子N 
21         printf("%d\n",f[m][n]);
22     }
23     return 0;
24 }
View Code

 

posted @ 2015-11-07 20:31  PencilWang  阅读(305)  评论(2编辑  收藏  举报