HHUOJ 1423 拔河
题目描述
小明班里要举行一次拔河比赛,班主任决定将所有人分为两队,每个人都必须参加,两队人数之差不能超过1,并且两个队伍的体重之和要尽可能相近,当然相同是最好的了。
输入
输入包含多组测试数据。
每组输入的第一行是一个正整数n(2<=n<=100),表示共有n个人。
接下来n行,每行输入一个整数w(1<=w<=450),表示每个人的体重。
输出
对于每组输入,分别输出两个队伍的体重之和,按升序排序。
样例输入
3
100
90
200
样例输出
190 200
本来以为就是简单背包问题,后来经过别人提醒,要满足两组人数之差小于等于1,我们用
d
p
i
,
j
,
k
dp_{i,j,k}
dpi,j,k 表示
i
i
i 个人里面挑
j
j
j 个人能否组成体重为
k
k
k的小组,用
b
o
o
l
bool
bool 类型表示正负,那么可以得到状态转移方程:
1.第
i
i
i 个人没选中,
d
p
i
,
j
,
k
=
d
p
i
−
1
,
j
,
k
dp_{i,j,k}=dp_{i-1,j,k}
dpi,j,k=dpi−1,j,k
2.第
i
i
i 个人被选中,
d
p
i
,
j
,
k
=
d
p
i
−
1
,
j
−
1
,
k
−
w
[
i
]
dp_{i,j,k}=dp_{i-1,j-1,k-w[i]}
dpi,j,k=dpi−1,j−1,k−w[i]
考虑最优,故
d
p
i
,
j
,
k
=
d
p
i
−
1
,
j
,
k
∣
∣
d
p
i
−
1
,
j
−
1
,
k
−
w
[
i
]
dp_{i,j,k}=dp_{i-1,j,k}||dp_{i-1,j-1,k-w[i]}
dpi,j,k=dpi−1,j,k∣∣dpi−1,j−1,k−w[i]
写代码时可以把三维优化成二维,AC代码如下:
#include <bits/stdc++.h>
using namespace std;
int a[105],dp[105][45500];
int main()
{
int n;
while(cin>>n)
{
int s=0;
memset(dp,0,sizeof(dp));
for(int i=1;i<=n;i++)
{
scanf("%d",&a[i]);
s+=a[i];
}
dp[0][0]=1;
for(int i=1;i<=n;i++)
{
for(int j=i;j;j--)
{
for(int k=s;k>=a[i];k--)
dp[j][k]|=dp[j-1][k-a[i]];//按位或
}
}
int mid=n>>1,ans;
for(ans=s>>1;!dp[mid][ans]&&!dp[n-mid][ans];ans--);
cout<<ans<<" "<<s-ans<<endl;
}
return 0;
}