猫狗大战
题目描述
新一年度的猫狗大战通过SC(星际争霸)这款经典的游戏来较量,野猫和飞狗这对冤家为此已经准备好久了,为了使战争更有难度和戏剧性,双方约定只能选择Terran(人族)并且只能造机枪兵。
比赛开始了,很快,野猫已经攒足几队机枪兵,试探性的发动进攻;然而,飞狗的机枪兵个数也已经不少了。野猫和飞狗的兵在飞狗的家门口相遇了,于是,便有一场腥风血雨和阵阵惨叫声。由于是在飞狗的家门口,飞狗的兵补给会很快,野猫看敌不过,决定撤退。这时飞狗的兵力也不足够多,所以没追出来。
由于不允许造医生,机枪兵没办法补血。受伤的兵只好忍了。555-
现在,野猫又攒足了足够的兵力,决定发起第二次进攻。为了使这次进攻给狗狗造成更大的打击,野猫决定把现有的兵分成两部分,从两路进攻。由于有些兵在第一次战斗中受伤了,为了使两部分的兵实力平均些,分的规则是这样的:1)两部分兵的个数最多只能差一个;2)每部分兵的血值总和必须要尽可能接近。现在请你编写一个程序,给定野猫现在有的兵的个数以及每个兵的血格值,求出野猫按上述规则分成两部分后每部分兵的血值总和。
输入输出格式
输入格式:第一行为一个整数n(1<=n<=200),表示野猫现在有的机枪兵的个数。以下的n行每行一个整数,表示每个机枪兵的血格(1<=ai<=40)。
输出格式:一行,为两个整数,表示分成两部分后每部分兵的血值总和
输入输出样例
说明
TO 狗狗:这道题的数据范围我已经尽量按星际的游戏规则来了,如果你再固执于由于机枪兵的攻击力一定使不能达到某些血格值或者游戏中一定要造农民不能使机枪兵的人数达到200的话,我只能决定将那场猫狗大战的录像公开于世人了!!!
【解题思路】
这道题可以用一种背包的思想来做,用f[i][j]表示j个士兵是否可以组成i的血量,因为两部分士兵数量悬殊不超过1,如果n为奇数,那就是一个n/2,一个n/2+1,如果是偶数,那就全是n/2,所以k只要枚举到n/2就行了,然后最后统计一下能构成的血量与总血量悬殊的最小值,然后输出的就是总的减去这个最小值和这个最小值。
下面是极其简洁的代码:
【code】
1 #include <cstdio> 2 #include <iostream> 3 #include <algorithm> 4 using namespace std; 5 int i,j,k,n,a[201],f[201][8001],s1,s2,sum,ans; 6 const int INF=1<<30; 7 inline int read(){ 8 int ans=0,ok=1; 9 char ch=getchar(); 10 while(ch<'0'||ch>'9') { 11 if(ch=='-')ok=-1; 12 ch=getchar(); 13 } 14 for (;ch>='0'&&ch<='9';ch=getchar()) 15 ans=ans*10+ch-'0'; 16 return ans*ok; 17 } 18 inline int Min(int a,int b){ 19 return a<b?a:b; 20 } 21 inline int Max(int a,int b){ 22 return a>b?a:b; 23 } 24 int main(){ 25 //freopen("1489.in","r",stdin); 26 //freopen("1489.out","w",stdout); 27 n=read(); 28 for(i=1;i<=n;i++){ 29 a[i]=read(); 30 sum+=a[i]; 31 } 32 s1=sum/2; 33 s2=n/2+n%2; 34 for(i=1;i<=s2;i++) 35 for(j=0;j<=s1;j++) 36 f[i][j]=-INF; 37 for(k=1;k<=n;k++) 38 for(i=s2;i>=1;i--) 39 for(j=s1;j>=a[k];j--) 40 f[i][j]=Max(f[i][j],f[i-1][j-a[k]]+a[k]); 41 ans=Max(f[s2][s1],f[n/2][s1]); 42 printf("%d %d\n",ans,sum-ans); 43 return 0; 44 }