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;
            }
        }

    } 

} 
时间: 2024-11-05 12:06:41

lightoj-1147 - Tug of War(状压dp)的相关文章

lightoj 1057 - Collecting Gold(状压dp)

题目链接:http://www.lightoj.com/volume_showproblem.php?problem=1057 题解:看似有点下记忆话搜索但是由于他是能走8个方向的也就是说两点的距离其实就是最大的x轴或y轴的差.然后只有15个藏金点状压一下加dfs就行了. #include <iostream> #include <cstring> #include <cstdio> #include <cmath> #define inf 0X3f3f3f

lightoj 1119 - Pimp My Ride(状压dp)

题目链接:http://www.lightoj.com/volume_showproblem.php?problem=1119 题解:状压dp存一下车有没有被搞过的状态就行. #include <iostream> #include <cstring> #include <cstdio> using namespace std; typedef long long ll; ll dp[1 << 15] , val[15][15]; int main() {

ZOJ3305Get Sauce 状压DP,

状压DP的题目留个纪念,首先题意一开始读错了,搞了好久,然后弄好了,觉得DFS可以,最后超时,修改了很久还是超时,没办法看了一下n的范围,然后觉得状压可以,但是没有直接推出来,就记忆化搜索了一下,可是一直错,莫名奇妙,然后没办法看了一下题解,发现了下面这个比较好的方法,然后按照这个方程去推,然后敲,也是WA了好多把,写的太搓了,没人家的清楚明了,唉~也算是给自己留个纪念,状压一直做的都不太好~唉~还好理解了, 参考了  http://blog.csdn.net/nash142857/articl

poj 2411 Mondriaan&#39;s Dream(状压DP)

Mondriaan's Dream Time Limit: 3000MS   Memory Limit: 65536K Total Submissions: 12232   Accepted: 7142 Description Squares and rectangles fascinated the famous Dutch painter Piet Mondriaan. One night, after producing the drawings in his 'toilet series

(状压dp)uva 10817 Headmaster&#39;s Headache

题目地址 1 #include <bits/stdc++.h> 2 typedef long long ll; 3 using namespace std; 4 const int MAX=1e5+5; 5 const int INF=1e9; 6 int s,m,n; 7 int cost[125]; 8 //char sta[MAX]; 9 string sta; 10 int able[125]; 11 int dp[125][1<<8][1<<8]; 12 in

HDU5816 Hearthstone(状压DP)

题目 Source http://acm.hdu.edu.cn/showproblem.php?pid=5816 Description Hearthstone is an online collectible card game from Blizzard Entertainment. Strategies and luck are the most important factors in this game. When you suffer a desperate situation an

HDU 4336 容斥原理 || 状压DP

状压DP :F(S)=Sum*F(S)+p(x1)*F(S^(1<<x1))+p(x2)*F(S^(1<<x2))...+1; F(S)表示取状态为S的牌的期望次数,Sum表示什么都不取得概率,p(x1)表示的是取x1的概率,最后要加一因为有又多拿了一次.整理一下就可以了. 1 #include <cstdio> 2 const int Maxn=23; 3 double F[1<<Maxn],p[Maxn]; 4 int n; 5 int main() 6

Travel(HDU 4284状压dp)

题意:给n个城市m条路的网图,pp在城市1有一定的钱,想游览这n个城市(包括1),到达一个城市要一定的花费,可以在城市工作赚钱,但前提有工作证(得到有一定的花费),没工作证不能在该城市工作,但可以走,一个城市只能工作一次,问pp是否能游览n个城市回到城市1. 分析:这个题想到杀怪(Survival(ZOJ 2297状压dp) 那个题,也是钱如果小于0就挂了,最后求剩余的最大钱数,先求出最短路和 Hie with the Pie(POJ 3311状压dp) 送披萨那个题相似. #include <

BZOJ 1087: [SCOI2005]互不侵犯King( 状压dp )

简单的状压dp... dp( x , h , s ) 表示当前第 x 行 , 用了 h 个 king , 当前行的状态为 s . 考虑转移 : dp( x , h , s ) = ∑ dp( x - 1 , h - cnt_1( s ) , s' ) ( s and s' 两行不冲突 , cnt_1( s ) 表示 s 状态用了多少个 king ) 我有各种预处理所以 code 的方程和这有点不一样 ------------------------------------------------