分糖果
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 }