题目链接
题目描述:
Nowadays, we all know that Computer College is the biggest department in HDU. But, maybe you don’t know that Computer College had ever been split into Computer College and Software College in 2002. The splitting is absolutely a big event in HDU! At the same time, it is a trouble thing too. All facilities must go halves. First, all facilities are assessed, and two facilities are thought to be same if they have the same value. It is assumed that there is N (0<N<1000) kinds of facilities (different value, different kinds).
题目翻译:
如今,我们都知道计算机学院是杭电最大的系。但是,你或许不知道计算机学院在2002年被划分为计算机学院和软件学院,这在杭电绝对称得上是一件大事,同时也是一件麻烦的事。所有的设备要尽可能平均地分到两个学院(指两个学院得到的设备的价值尽可能平均)。首先所有的设备都经过评估,如果两个设备的价值相同,这两个设备则被认为是相同的。这里假设有N种设备(不同的价值),每种设备的价值为V,数量为M。输出A和B,分别代表两个学院最后分到的设备的总价值,其中A不小于B。
解题思路:
可以发现,这是一道多重背包问题。
题目要求所有的设备尽可能平均地分到两个学院,那么可以知道其中一个学院B分到的设备的价值要尽可能接近总价值的一半,另一个学院A得到的价值就是总价值-B得到的价值。
如此一来,我们可以用数组f[i][j] 表示前 i 个物品,价值为 j(相当于背包的容量)时能得到的最大价值。最后学院B得到的价值就是f[n][sum/2]
,其中sum表示总价值,学院A得到的价值就是sum-f[n][sum/2]
。
代码部分就和其他多重背包问题大同小异了,如果看不懂,可以参考我之前写得博客
多重背包问题(暴力、二进制优化、单调队列优化)
并且这里需要把二维数组f优化成一维的,不然会超内存,可以参考这篇博客
01背包问题的“优化空间复杂度:O(N*V)->O(V)”部分
代码:
#include<iostream>
#include<cstring>
#include<string>
#include<algorithm>
#include<vector>
#include<map>
#include<queue>
#include<cstdio>
#include<cmath>
#define inf 0x3f3f3f3f
using namespace std;
const int N = 251000;
int f[N],v[60],m[60];
int main() {
// freopen("1.txt","r",stdin);
int n,sum=0;
while(cin>>n&&n>0) {
memset(f,0,sizeof f);
f[0]=0;
sum=0;
for(int i=1;i<=n;i++){
cin>>v[i]>>m[i];
sum+=v[i]*m[i];
}
for(int i=1; i<=n; i++) {
for(int j=sum; j>=1; j--) {
for(int k=1; k<=m[i]; k++) {
if(j>=v[i]*k) {
f[j]=max(f[j],f[j-v[i]*k]+v[i]*k);
}
}
}
}
int a,b;
a=f[sum/2],b=sum-a;
cout<<max(a,b)<<" "<<min(a,b)<<endl;
}
return 0;
}
总结:
题目是不难写了,就是有些细节需要注意,因为细节WA了好几次。