POJ1015-Jury Compromise-dp
略复杂的dp题。
有n个人,每个人有两个分数di,pi。从中选出m个人,要求|sigma(di)-sigma(pi)|最小,相同时则输出sigma(di)+sigma(pi)最大的情况。
答案完整输出方案。
dp[i][j]表示i个人的组合里,差值为j的情况下,和值的最大值。
计算每一个人的差值subi,和值sumi
则dp[i][j] = max(dp[i-1][j-subk]+sumk) k∈n
注意dp的时候为了能表示负数,要加一个修正值。
1 #include <cstdio> 2 #include <cstring> 3 #include <algorithm> 4 5 using namespace std; 6 7 const int maxn = 200+10; 8 const int X = 500; 9 const int INF = 0x3f3f3f3f; 10 11 int n,m; 12 int sum[maxn],sub[maxn]; 13 int dp[25][10*maxn]; 14 int path[25][10*maxn]; 15 16 bool check(int i,int j,int k) 17 { 18 int tmp ; 19 while(path[i][X+j]) 20 { 21 tmp = path[i][X+j]; 22 if(k == tmp) 23 return false; 24 j -= sub[tmp]; 25 i--; 26 } 27 return true; 28 } 29 30 int main() 31 { 32 int cas = 0; 33 while(scanf("%d%d",&n,&m) && n) 34 { 35 int d,p; 36 cas++; 37 for(int i=1;i<=n;i++) 38 { 39 scanf("%d%d",&p,&d); 40 sum[i] = p+d; 41 sub[i] = p-d; 42 } 43 memset(dp,-1,sizeof dp); 44 memset(path,0,sizeof path); 45 46 dp[0][X+0] = 0; 47 48 int ans_sub = 400+5; 49 for(int i=1;i<=m;i++) 50 { 51 for(int j=-400;j<=400;j++) 52 { 53 for(int k=1;k<=n;k++)if(dp[i-1][X+j-sub[k]] != -1 && check(i-1,j-sub[k],k)) 54 { 55 if(dp[i-1][X+j-sub[k]]+sum[k] > dp[i][X+j]) 56 { 57 dp[i][X+j] = dp[i-1][X+j-sub[k]]+sum[k]; 58 path[i][X+j] = k; 59 //printf("i:%d j:%d k:%d dp:%d\n",i,j,k,dp[i][X+j]); 60 if(i==m && ( abs(j) < abs(ans_sub) || (abs(j)==abs(ans_sub) && dp[i][X+j] > dp[i][X+ans_sub]) ) ) 61 { 62 ans_sub = j; 63 } 64 } 65 } 66 } 67 } 68 69 //printf("%d\n",ans_sub); 70 printf("Jury #%d\n",cas); 71 printf("Best jury has value %d for prosecution and value %d for defence: \n",(dp[m][X+ans_sub]+ans_sub)/2,(dp[m][X+ans_sub]-ans_sub)/2); 72 73 int ans[25],cnt=0; 74 for(int i=m;i>=1;i--) 75 { 76 ans[cnt++] = path[i][X+ans_sub]; 77 ans_sub -= sub[ans[cnt-1]]; 78 } 79 sort(ans,ans+cnt); 80 81 for(int i=0;i<cnt;i++) 82 { 83 printf(" %d",ans[i]); 84 } 85 printf("\n\n"); 86 } 87 }
最近dp写的略顺手