题目
题目描述
新一年度的猫狗大战通过SC(星际争霸)这款经典的游戏来较量,野猫和飞狗这对冤家为此已经准备好久了,为了使战争更有难度和戏剧性,双方约定只能选择Terran(人族)
并且只能造机枪兵。
比赛开始了,很快,野猫已经攒足几队机枪兵,试探性的发动进攻;然而,飞狗的机枪兵个数也已经不少了。野猫和飞狗的兵在飞狗的家门口相遇了,于是,便有一场腥风血雨和阵阵惨叫声。由于是在飞狗的家门口,飞狗的兵补给会很快,野猫看敌不过,决定撤退。这时飞狗的兵力也不足够多,所以没追出来。
由于不允许造医生,机枪兵没办法补血。受伤的兵只好忍了。 555 555 555~
现在,野猫又攒足了足够的兵力,决定发起第二次进攻。为了使这次进攻给狗狗造成更大的打击,野猫决定把现有的兵分成两部分,从两路进攻。由于有些兵在第一次战斗中受伤了,为了使两部分的兵实力平均些,分的规则是这样的:
1)两部分兵的个数最多只能差一个;
2)每部分兵的血值总和必须要尽可能接近。
现在请你编写一个程序,给定野猫现在有的兵的个数以及每个兵的血格值,求出野猫按上述规则分成两部分后每部分兵的血值总和。
输入格式
第一行为一个整数 n ( 1 ≤ n ≤ 200 ) n(1 le n le 200) n(1≤n≤200),表示野猫现在有的机枪兵的个数。以下的n行每行一个整数,表示每个机枪兵的血格 ( 1 ≤ a i ≤ 40 ) (1le a_i le 40) (1≤ai≤40)
输出格式
只有一行,包含两个数,即野猫的每部分兵的血值总和,较小的一个值放在前面,两个数用空格分隔。
样例输入
3
35
20
32
样例输出
35 52
题解
写在前面:网上有的题解是可以被轻松hack的,所以我决定自己写一篇来作为总结,欢迎来hack我
hack数据:
3
10 10 21
如果没有兵的个数的限制,本题就是一道普普通通的01背包裸题,只需以 s u m 2 frac{sum}{2} 2sum为背包总容量,每个物品的体积和价值都为血量即可
结合优化空间的01背包的思想,
b
o
o
l
bool
bool
d
p
i
,
j
dp_{i,j}
dpi,j表示选了前
i
i
i个兵,总血量为
j
j
j可不可行,现在考虑在以可行的
d
p
i
,
j
dp_{i,j}
dpi,j中加入一个兵
k
k
k,他的血量为
a
k
a_k
ak,那么加入他后
d
p
i
+
1
,
j
+
a
k
dp_{i+1,j+a_k}
dpi+1,j+ak一定可行
所以得到我们的状态转移方程:
if (dp[j][k]){
dp[j+1][k+a[i]]=1;
}
由于题目需要血量尽可能的接近,所以我们从 s u m 2 frac{sum}{2} 2sum到 0 0 0开始枚举血量,只要人数对应这个血量可以满足,就输出这组血量并结束程序(因为从 s u m 2 frac{sum}{2} 2sum开始枚举血量,所以首先枚举到的肯定是最优的)
for(int i=sum/2;i>=0;i--){
if(dp[n/2][i]||(dp[n/2+1][i] && n%2==1)){
printf("%d %d",i,sum-i);
break;
}
}
其实这算是一个二维费用背包 + 可行性的综合题目二维费用很好想到,主要需要想到可行性的如何实现,和最后该如何遍历得到最优解。
完整代码:
#include<iostream>
#include<algorithm>
using namespace std;
int a[205],dp[205][8005];
int main() {
int n,sum=0;
scanf("%d",&n);
for(int i=1;i<=n;i++){
scanf("%d",&a[i]);
sum+=a[i];
}
dp[0][0]=1;
for(int i=1;i<=n;i++){
for (int j=n/2+1;j>=0;j--) {
for(int k=sum/2;k>=0;k--){
if (dp[j][k]) {
dp[j+1][k+a[i]]=1;
}
}
}
}
for(int i=sum/2;i>=0;i--){
if(dp[n/2][i]||(dp[n/2+1][i] && n%2==1)){
printf("%d %d",i,sum-i);
break ;
}
}
return 0;
}
最后
以上就是震动秀发最近收集整理的关于【题解】猫狗大战题目题解的全部内容,更多相关【题解】猫狗大战题目题解内容请搜索靠谱客的其他文章。
发表评论 取消回复