The first line of input contains n the number of people at the picnic. n lines follow. The first line gives the weight of person 1; the second the weight of person 2; and so on. Each weight is an integer between 1 and 450. There are at most 100 people at the picnic.
Your output will be a single line containing 2 numbers: the total weight of the people on one team, and the total weight of the people on the other team. If these numbers differ, give the lesser first.
Sample Input
3 100 90 200
Output for Sample Input
190 200
Source: Waterloo Local Contest Sep. 30, 2000
这道题我们看作一个背包的容量是总质量的一半,并且要放总数量的一半的背包问题。
dp[j][k]=1状态表示背包放入k个物品时总质量为j。
#include <stdio.h> #include <iostream> #include <memory.h> using namespace std; int p[110],dp[45010][110]; int main(){ int i,j,k,n,sum,m; while(~scanf("%d",&n)){ memset(dp,0,sizeof(dp)); sum = 0; for(i=1;i<=n;i++){ scanf("%d",&p[i]); sum += p[i]; } m = (n+1)/2; dp[0][0] = 1; for(i=1;i<=n;i++){ for(j=sum/2;j>=p[i];j--){ for(k=m;k>0;k--){ if(dp[j-p[i]][k-1]) dp[j][k] = 1; } } } for(i=sum/2;i>0;i--){ if(n%2==0) { if(dp[i][m]==1) break; } else { if(dp[i][m]==1||dp[i][m-1]==1) break; } } printf("%d %d\n",i,sum-i); } return 0; }
然而这道题的数据还是有漏洞的。由于限定两个背包中数量相差不超过1,所以将上述状态降为成如下状态是不行的:
dp[j]=k表示当背包内放k个物品时质量为j,该状态代码如下
#include <stdio.h> #include <iostream> #include <memory.h> using namespace std; int p[110],dp[45010]; int main(){ int i,j,k,n,sum,m; while(~scanf("%d",&n)){ memset(dp,0,sizeof(dp)); sum = 0; for(i=1;i<=n;i++){ scanf("%d",&p[i]); sum += p[i]; } m = (n+1)/2; dp[0] = 1; for(i=1;i<=n;i++){ for(j=sum/2;j>=0;j--){ if(dp[j] && dp[j]<=m && j+p[i]<=sum/2){ if(!dp[j+p[i]]) dp[j+p[i]] = dp[j]+1; else dp[j+p[i]] = min(dp[j+p[i]],dp[j]+1); } } } for(i = sum/2;i>=0;i--) if(dp[i]){ break; } printf("%d %d\n",i,sum-i); } return 0; }
显然这个代码无法限制两背包数量之差。如4个物品质量为100,20,30,50时,输出应为80,120而不是100,100。