分糖果

f[i][j][k]表示前i个糖果,取了j个,ri和fi的差值为k时的最大和,转移时有三种情况,不取,增大差值,减小差值。注意不要越界,一开始的差值为0可以用400来表示,这样不会让数组出现负的下标,f[i][j][k]=MAX(f[i-1][j][k],f[i-1][j-1][k-(r[i]-f[i])]+r[i]+f[i]),如果f[i][j][k]上被更新过,则代表有这种可能性,所以答案为f[n][m][k-i],i=0,1,2….找到i最小的被更新过的位置则为答案。

         自己一开始用的f[i][j]表示前i个取j个的最小k值,同时另开两个数组表示cigma(r,f),

但是忽略了这样做的后效性。

 1 #include<cstdio>
 2 #include<cstring>
 3 using namespace std;
 4 int m,n;
 5 int f[205][22][821];
 6 int MAX(int a,int b){
 7     if(a>b) return a;
 8     else return b;
 9 }
10 int r[205],l[205];
11 int ABS(int x,int y){
12     x-=y;
13     return -x;
14 }
15 int main(){
16     
17     memset(f,-0x3f,sizeof(f));
18     scanf("%d%d",&n,&m);
19     for(int i=1;i<=n;i++){
20         scanf("%d%d",&l[i],&r[i]);
21         f[i][0][400]=0;
22     }
23     f[0][0][400]=0;
24      for(int i=1;i<=n;i++){
25         for(int j=1;j<=m;j++){
26             if(j>i) break;
27             for(int k=10;k<=800;k++){
28                 f[i][j][k]=MAX(f[i-1][j-1][k-(l[i]-r[i])]+r[i]+l[i],f[i-1][j][k]);
29         //        if(f[i][j][k]>0) printf("f[%d][%d][%d] =%d\n",i,j,k,f[i][j][k]);
30             }
31         }
32     }
33     for(int i=0;i<=400;i++){
34         if(f[n][m][400+i]>0&&f[n][m][400-i]>0){
35             printf("%d\n%d",i,MAX(f[n][m][400-i],f[n][m][400+i]));
36             break;
37         }
38         if(f[n][m][400+i]>0){
39             printf("%d\n%d",i,f[n][m][400+i]);
40             break;
41         }
42         if(f[n][m][400-i]>0){
43             printf("%d\n%d",i,f[n][m][400-i]);
44             break;
45         }
46     }
47 //    printf("\n%d\n",f[1][1][399]);
48     getchar(); getchar();
49 }
View Code

 

posted @ 2015-10-11 18:33  Lenicodes  阅读(177)  评论(0编辑  收藏  举报