猫狗大战

题目描述

新一年度的猫狗大战通过SC(星际争霸)这款经典的游戏来较量,野猫和飞狗这对冤家为此已经准备好久了,为了使战争更有难度和戏剧性,双方约定只能选择Terran(人族)并且只能造机枪兵。

比赛开始了,很快,野猫已经攒足几队机枪兵,试探性的发动进攻;然而,飞狗的机枪兵个数也已经不少了。野猫和飞狗的兵在飞狗的家门口相遇了,于是,便有一场腥风血雨和阵阵惨叫声。由于是在飞狗的家门口,飞狗的兵补给会很快,野猫看敌不过,决定撤退。这时飞狗的兵力也不足够多,所以没追出来。

由于不允许造医生,机枪兵没办法补血。受伤的兵只好忍了。555-

现在,野猫又攒足了足够的兵力,决定发起第二次进攻。为了使这次进攻给狗狗造成更大的打击,野猫决定把现有的兵分成两部分,从两路进攻。由于有些兵在第一次战斗中受伤了,为了使两部分的兵实力平均些,分的规则是这样的:1)两部分兵的个数最多只能差一个;2)每部分兵的血值总和必须要尽可能接近。现在请你编写一个程序,给定野猫现在有的兵的个数以及每个兵的血格值,求出野猫按上述规则分成两部分后每部分兵的血值总和。

输入输出格式

输入格式:

 

第一行为一个整数n(1<=n<=200),表示野猫现在有的机枪兵的个数。以下的n行每行一个整数,表示每个机枪兵的血格(1<=ai<=40)。

 

输出格式:

 

一行,为两个整数,表示分成两部分后每部分兵的血值总和

 

输入输出样例



复制

3 35 20 32



复制

35 52



说明

TO 狗狗:这道题的数据范围我已经尽量按星际的游戏规则来了,如果你再固执于由于机枪兵的攻击力一定使不能达到某些血格值或者游戏中一定要造农民不能使机枪兵的人数达到200的话,我只能决定将那场猫狗大战的录像公开于世人了!!!



for(int i=1;i<=n;i++)
        for(int j=n>>1;j;j--)
            for(int k=sum;k>=a[i];k--)
                dp[j][k]|=dp[j-1][k-a[i]];
//i记录前i个人,j记录共j个人,k记录一共得血量 dp[j][k]的值为它前一个的值或自己已经有的值 所以一定要注意边界dp[0][0]=true



注:a|=b

其实这就是把十进制数转为二进制数,也就是各个数位只有“1”或“0”,那么如果a的二进制数或b的二进制数中第i位有任意一个是1的话,那么a|=b的第i位也是1,相反,如果都没有1的话,那么a|=b的第i位就等于0,看上去没啥用,但用在bool类型就有用了,bool本来就是二进制,也就是如果a,b都是bool类型,那么a|=b就如果a和b中有任意一个true就返回true否则返回false



1 #include<stdio.h>
 2 using namespace std;
 3 int sum=0,a[210],dp[210][8100];
 4 int main()
 5 {
 6     scanf("%d",&n);
 7     dp[0][0]=1;
 8     for(int i=1;i<=n;i++)
 9     {
10         scanf("%d",&a[i]);
11         sum+=a[i];
12     }
13     for(int i=1;i<=n;i++)
14         for(int j=n>>1;j;j--)
15             for(int k=sum;k>=a[i];k--)
16                 dp[j][k]|=dp[j-1][k-a[i]];
17     for(int i=sum>>1;i>=0;i--)
18         if(dp[n>>1][i])
19         {
20             printf("%d %d",i,sum-i);
21             return 0;
22         }
23 }