[poj1015]Jury Compromise[DP]

题意:$n$个物品选$m$个,每个物品有两个权值$A[i]$和$B[i]$,要求选出的$m$个物品$left|sum A[i]-sum B[i] ight|$最小,当这个差值相同时,选择$sum A[i]+sum B[i]$最大的,输出$sum A[i]$,$sum B[i]$,方案。

题解:

令$V=left|sum A[i]-sum B[i] ight|$

$S=sum A[i]+sum B[i]$   

$s[i]=A[i]+B[i]$

$v[i]=A[i]-B[i]$

设$f[j][k]$表示选过第$j$个后 $k=sum A[i]-sum B[i]$(注意没有绝对值) 时$S$的最大值,若$f[j][k]==-1$表示不存在合法方案。

$path[j][k]$表示$f[j][k]$是由$f[j-1][k]$选择了$path[j][k]$后得到的,即状态$f[j][k]$处最后选择的物品。

最后方案的输出用$path$数组向前回溯,考虑$path[j][k]$的前一个选的是$path[j-1][k-v[path[j][k]]]$。

转移如下:

if (f[j-1][k]+s[i] > f[j][k+v[i]] && !Selected(j-1,k,i) )//i没有被之前的状态选择
	f[j][k+v[i]]=f[j-1][k]+s[i], path[j][k+v[i]]=i;

这样最终答案是$left| k ight|$最小的合法$f[m][k](f[m][k]!=-1)$。

因为$f[m][k]=sum A[i]+sum B[i]$

$k=sum A[i]-sum B[i]$

所以答案的$sum A[i]=(f[m][k]+k)/2$

$sum B[i]=(f[m][k]-k)/2$

最后,方案的输出用$path$数组向前回溯,考虑$path[j][k]$的前一个选的是$path[j-1][k-v[path[j][k]]]$。

将得到的方案排序输出即可。 为了避免负数下表,要将第二维平移,需注意细节。

 1 #include <iostream>
 2 #include <algorithm>
 3 #include <cstdio>
 4 #include <cstdlib>
 5 #include <cstring>
 6 #include <ctime>
 7 #include <cmath>
 8 #include <vector>
 9 
10 using namespace std;
11 
12 int    n,m,a[210],b[210],v[210],s[210],fix,Kase;
13 int    f[1100][1100],path[1100][1100];
14 
15 bool    Selected(int j,int k,const int i)
16 {
17     while(j>0 && path[j][k]!=i)  
18         {  k-=v[path[j][k]]; j--; }  
19     return j; 
20 }
21 
22 int main()
23 {
24     while (~scanf("%d%d",&n,&m) && n && m)
25     {
26         for (int i=1;i<=n;++i)
27             scanf("%d%d",&a[i],&b[i]),
28               v[i]=a[i]-b[i],s[i]=a[i]+b[i];
29         
30         fix=m*20; memset(f,0xff,sizeof(f)); f[0][fix]=0;
31 
32         for (int j=1;j<=m;++j) for (int k=0;k<=fix<<1;++k)
33         {
34             if (f[j-1][k]<0)continue;
35             for (int i=1;i<=n;++i)
36             {
37                 if (f[j-1][k]+s[i] > f[j][k+v[i]] && 
38                     !Selected(j-1,k,i) )
39                 {
40                     f[j][k+v[i]]=f[j-1][k]+s[i];
41                     path[j][k+v[i]]=i;
42         }    }    }
43 
44         int tt; for(int k=0;k<=fix;++k)
45             if(f[m][fix-k]>=0 || f[m][fix+k]>=0) { tt=k; break; }
46 
47         int temp=(f[m][fix-tt]>f[m][fix+tt]?(fix-tt):(fix+tt));
48         printf("Jury #%d
Best jury has value %d for prosecution and"
49             " value %d for defence: 
",++Kase,
50               (f[m][temp]+temp-fix)>>1,(f[m][temp]-temp+fix)>>1);
51 
52         vector<int>    vec; tt=temp;
53         for(int j=m;j;--j)
54         { vec.push_back(path[j][tt]); tt-=v[vec.back()]; }
55 
56         sort(vec.begin(),vec.end());
57         for(int i=0;i<(int)vec.size();++i) printf(" %d",vec[i]);
58 
59         printf("
");
60     }
61     return 0;
62 }
原文地址:https://www.cnblogs.com/Gster/p/5617772.html