题目大意
给出n( ≤ 100 \le100 ≤100)个人的重量( ≤ 450 \le450 ≤450),把他们分成两组,两组的人数差不超过1,使两个组内所有人体重相加尽可能接近。
解题思路
单看题面,我们不能发现这题跟dp有什么关系,因为当人数为
n
−
1
n-1
n−1的方案为最优时,我们不能保证
n
n
n的方案最优,因此不能从人数方面考虑dp,但题目中说了每个人的体重不超过450,,经过思考,我们发现可以将体重作为数组下标,用
f
[
i
,
j
,
k
]
f[i,j,k]
f[i,j,k]表示当前i个人中选j个人在一组时能否组成重量为k的方案。因为
f
[
i
,
j
,
k
]
f[i,j,k]
f[i,j,k]有两种情况,选与不选,若是选,那么就从
f
[
i
−
1
,
j
−
1
,
k
−
w
[
i
]
]
f[i-1,j-1,k-w[i]]
f[i−1,j−1,k−w[i]]得到,若是不选就从
f
[
i
−
1
,
j
−
1
,
k
]
f[i-1,j-1,k]
f[i−1,j−1,k]得到。所以得到转移方程:
f
[
i
,
j
,
k
]
=
f
[
i
−
1
]
[
j
−
1
]
[
k
−
w
[
i
]
]
o
r
f
[
i
−
1
]
[
j
−
1
]
[
k
]
f[i,j,k]=f[i-1][j-1][k-w[i]] \ or \ f[i-1][j-1][k]
f[i,j,k]=f[i−1][j−1][k−w[i]] or f[i−1][j−1][k]
代码
#include<iostream>
#include<cstdio>
#include<cmath>
using namespace std;
int n,w[110],a,ans,ans1;
bool f[110][50005];
int main()
{
cin>>n;
for(int i=1;i<=n;i++) cin>>w[i],a+=w[i];//a为两组之和
f[0][0]=1;//初始化
for(int i=1;i<=n;i++)//枚举总人数
for(int j=1;j<=i/2+1;j++)//枚举每组人数
for(int k=450*j;k>=max(j,w[i]);k--)//枚举重量
f[j][k]=f[j-1][k-w[i]]||f[j][k];
for(int i=a/2;i>=0;i--)//枚举其中一组的人数,从大到小枚举
{
if(f[n/2][i]||f[n/2+1][i]) //如果存在则输出
{
cout<<i<<" "<<a-i;
return 0;
}
}
return 0;
}