poj1015陪审团——DP+路径记录
题目:http://poj.org/problem?id=1015
DP的第一维是选了几个人,第二维是当前D与P的差值,而值存的是当前D与P的和;
技巧1:通过平移避免负角标,即代码中的fix;
技巧2:做完DP后找出最小的差的绝对值时,如下的那一小段代码很有效率;
技巧3(*):记录路径——①更新路径时每次判断是否重复选了一个人,重复则不更新;
if(f[j][k]+P[i]+D[i]>f[j+1][k+P[i]-D[i]]) { t1=j;t2=k; while(t1>0&&Path[t1][t2]!=i)//验证i是否在前面出现过 { t2-=P[Path[t1][t2]]-D[Path[t1][t2]]; t1--; } if(t1==0) { f[j+1][k+P[i]-D[i]]=f[j][k]+P[i]+D[i]; Path[j+1][k+P[i]-D[i]]=i; } }
int tmp=mk; for(int j=m;j>0;j--) { int pr=pre[j][tmp]; ans[j]=pr; tmp-=(a[pr]-b[pr]); } sort(ans+1,ans+m+1);
②使用vector,每次更新暴力复制;(下面采用)
if(dp[i+1][j+subtraction[k]] <= dp[i][j] + _plus[k]) { dp[i+1][j+subtraction[k]] = dp[i][j] + _plus[k]; path[i+1][j+subtraction[k]] = path[i][j];//每次更新都要把path全部复制过来,就是因为这个才用的vector path[i+1][j+subtraction[k]].push_back(k); }
注意:(不知为何)DP顺序,必须是i+1被i更新,原来写的是i被i-1更新,一直WA。
代码如下:
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #include<vector> using namespace std; int n,m,a[205],b[205],f[25][805],fix,t,ans[205]; vector<int>pre[25][805]; int main() { while(scanf("%d%d",&n,&m)==2) { t++; memset(f,-1,sizeof f); memset(ans,0,sizeof ans); memset(pre,0,sizeof pre); if(!n&&!m)return 0; for(int i=1;i<=n;i++) scanf("%d%d",&a[i],&b[i]); fix=20*m; // for(int k=0;k<=2*fix;k++)f[0][k]=0; f[0][fix]=0; for(int i=1;i<=n;i++)//第i个人 for(int j=m-1;j>=0;j--)//选了j个 for(int k=0;k<=2*fix;k++) { // if(f[j-1][k-a[i]+b[i]]<0)continue;// // if(f[j][k]<f[j-1][k-a[i]+b[i]]+a[i]+b[i]) // { // f[j][k]=f[j-1][k-a[i]+b[i]]+a[i]+b[i]; //// pre[j][k]=i; // pre[j][k]=pre[j-1][k-a[i]+b[i]]; // pre[j][k].push_back(i); // } if(f[j][k] >= 0) { if(f[j+1][k+a[i]-b[i]]<=f[j][k]+a[i]+b[i]) { f[j+1][k+a[i]-b[i]]=f[j][k]+a[i]+b[i] ; pre[j+1][k+a[i]-b[i]]=pre[j][k]; pre[j+1][k+a[i]-b[i]].push_back(i); } } } int mk; // for(int k=fix;k<=2*fix;k++) // if(f[m][k]>0) // { // mk=k;break; // } // for(int k=fix;k>=0;k--) // { // if(fix-k>=mk-fix)break; // if(f[m][k]>0) // { // mk=k;break; // } // } int j=0; while(f[m][fix-j]<0&&f[m][fix+j]<0)j++; if(f[m][fix-j]>f[m][fix+j])mk=fix-j; else mk=fix+j; int d=(f[m][mk]+(mk-fix))/2; int p=(f[m][mk]-(mk-fix))/2; // int tmp=mk; // for(int j=m;j>0;j--) // { // int pr=pre[j][tmp]; // ans[j]=pr; // tmp-=(a[pr]-b[pr]); // } // sort(ans+1,ans+m+1); printf("Jury #%d\nBest jury has value %d for prosecution and value %d for defence:\n",t,d,p); for(int i=0;i<m;i++) printf(" %d",pre[m][mk][i]); printf("\n\n"); } }