分糖果
2015-10-11 18:33
190 查看
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
[m][k-i],i=0,1,2….找到i最小的被更新过的位置则为答案。
自己一开始用的f[i][j]表示前i个取j个的最小k值,同时另开两个数组表示cigma(r,f),
但是忽略了这样做的后效性。
View Code
[m][k-i],i=0,1,2….找到i最小的被更新过的位置则为答案。
自己一开始用的f[i][j]表示前i个取j个的最小k值,同时另开两个数组表示cigma(r,f),
但是忽略了这样做的后效性。
#include<cstdio> #include<cstring> using namespace std; int m,n; int f[205][22][821]; int MAX(int a,int b){ if(a>b) return a; else return b; } int r[205],l[205]; int ABS(int x,int y){ x-=y; return -x; } int main(){ memset(f,-0x3f,sizeof(f)); scanf("%d%d",&n,&m); for(int i=1;i<=n;i++){ scanf("%d%d",&l[i],&r[i]); f[i][0][400]=0; } f[0][0][400]=0; for(int i=1;i<=n;i++){ for(int j=1;j<=m;j++){ if(j>i) break; for(int k=10;k<=800;k++){ f[i][j][k]=MAX(f[i-1][j-1][k-(l[i]-r[i])]+r[i]+l[i],f[i-1][j][k]); // if(f[i][j][k]>0) printf("f[%d][%d][%d] =%d\n",i,j,k,f[i][j][k]); } } } for(int i=0;i<=400;i++){ if(f [m][400+i]>0&&f [m][400-i]>0){ printf("%d\n%d",i,MAX(f [m][400-i],f [m][400+i])); break; } if(f [m][400+i]>0){ printf("%d\n%d",i,f [m][400+i]); break; } if(f [m][400-i]>0){ printf("%d\n%d",i,f [m][400-i]); break; } } // printf("\n%d\n",f[1][1][399]); getchar(); getchar(); }
View Code