题意:从 n个人里面找到m个人 每个人有两个值 d p 满足在abs(sum(d)-sum(p)) 最小的前提下sum(d)+sum(p)最大
思路:dp[i][j] i个人中 和是 j 运用背包的思想 二维背包 i是人数容量,人数要符合背包思想,每次只插入一个,逆序枚举
j是sum(d)+sum(p)
注意:这题的标准解法有误:https://blog.csdn.net/lyy289065406/article/details/6671105 这是有误的解法
错误由 POJ dicuss 提出:
也就是说 如果 存在和1 3 5 <2 4 6 但是差值相同 但是1 3 5 6是最大的 然而这时候 dp[3][j]的路径是2 4 6的路径 就不能再选出 6来更新1 3 5 所以就会有后效性 dp不成立
正解参考:https://blog.csdn.net/glqac/article/details/22687243
正解运用了背包的思想 进行二维化 第一维表示背包人数容量 第二维表示和 这样能不重不漏把所有情况都枚举了
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<vector> 5 using namespace std; 6 const int maxn=900; 7 int dp[25][maxn],sub[250],Plus[250]; 8 vector<int>path[25][maxn]; 9 int main(){ 10 int n,m,kase=1; 11 while(scanf("%d%d",&n,&m)==2){ 12 if(n+m==0)break; 13 for(int i=0;i<m;i++){ 14 for(int j=0;j<maxn;j++){ 15 path[i][j].clear(); 16 } 17 } 18 memset(dp,-1,sizeof(dp)); 19 int a,b; 20 for(int i=0;i<n;i++){ 21 scanf("%d%d",&a,&b); 22 sub[i]=a-b; 23 Plus[i]=a+b; 24 } 25 int fix=20*m; 26 dp[0][fix]=0; 27 for(int k=0;k<n;k++){ 28 for(int i=m-1;i>=0;i--){ 29 for(int j=0;j<fix*2;j++){ 30 if(dp[i][j]>=0){ 31 if(dp[i+1][j+sub[k]]<dp[i][j]+Plus[k]){ 32 dp[i+1][j+sub[k]]=dp[i][j]+Plus[k]; 33 path[i+1][j+sub[k]]=path[i][j]; 34 path[i+1][j+sub[k]].push_back(k); 35 } 36 } 37 } 38 } 39 } 40 int i; 41 for( i=0;dp[m][fix-i]==-1&&dp[m][fix+i]==-1;i++); 42 int temp=dp[m][fix+i]>dp[m][fix-i]?i:-i; 43 int sumD = ( dp[m][fix+temp] + temp )/2; 44 int sumP = ( dp[m][fix+temp] - temp )/2; 45 //辩方总值 = (辨控和+辨控差+修正值)/2 46 //控方总值 = (辨控和-辨控差+修正值)/2 47 printf( "Jury #%d ", kase++ ); 48 printf( "Best jury has value %d for prosecution and value %d for defence: ", sumD,sumP); 49 for( i=0; i < m; i++ ) 50 printf( " %d", path[m][fix+temp][i]+1); 51 printf(" "); 52 53 54 } 55 return 0; 56 }