lightoj-1147 - Tug of War(状压dp)
1147 - Tug of War
PDF (English) Statistics Forum
Time Limit: 4 second(s) Memory Limit: 32 MB
A tug of war is to be arranged at the local office picnic. For the tug of war, the picnickers must be divided into two teams. Each person must be on one team or the other; the number of people on the two teams must not differ by more than 1; the total weight of the people on each team should be as nearly equal as possible.
Input
Input starts with an integer T (≤ 100), denoting the number of test cases.
The first line of each case is a blank line. The next line of input contains an integer n (2 ≤ n ≤ 100), 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 100000. The summation of all the weights of the people in a case will not exceed 100000.
Output
For each case, print the case number and the total number weights of the people in two teams. If the weights differ, print the smaller weight first.
Sample Input
Output for Sample Input
2
3
100
90
200
4
10
15
17
20
Case 1: 190 200
Case 2: 30 32
解题思路: 这道题的大致思路就是01背包。 但是注意题目有一个条件,就是两队人数相差不过1。 所以不能只是单纯的01背包,我们算出最接近平均值的数的时候还要判断他否可以n/2 || n/2+1 个人组成。所以这道题在用01背包的基本模板计算时还要将可由几个人组成这个数的人数记录下来。一看需要记录状态的基本上就是状态压缩没有错了
因为n<=100, 所以要记录至多50位, 要用long long 来保存
ll dp[w] = m ,w为重量,m为二进制记录。 m的第i位表示由i-1个人构成(因为初始化必须要dp[0]=1,但dp[0]虽然有1,但它是没有人构成他) ,则如果是110,则表示可由1个人构成,也可由2个人构成。
综上可得转移方程 dp[w] = dp[w]|(dp[w-arr[i]]<<1);
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> using namespace std; typedef long long ll; ll dp[50010]; ll arr[110]; bool judge(ll x,ll n){ if(n%2==0){ int num = n/2; return (x&(1ll<<num))!=0; }else{ int num=n/2; return (x&(1ll<<num))!=0||(x&(1ll<<(num+1)))!=0; } } int main(){ ll sum,T,n; scanf("%lld",&T); for(ll t=1;t<=T;t++){ memset(dp,0,sizeof(dp)); scanf("%lld",&n); sum = 0; for(ll i=0;i<n;i++){ scanf("%lld",&arr[i]); sum+=arr[i]; } dp[0] = 1; for(ll i=0;i<n;i++){ for(ll j=sum/2;j>=arr[i];j--){ dp[j] = dp[j]|(dp[j-arr[i]]<<1); } } for(ll i=sum/2;i>=0;i--){ if(judge(dp[i],n)){ printf("Case %lld: %lld %lld\n",t,i,sum-i); break; } } } }