您的位置:首页 > 其它

hdu 1059 Dividing 多重背包

2017-09-08 13:02 393 查看
传送门http://acm.hdu.edu.cn/showproblem.php?pid=1059

题意:

给出6个数字a[1]~a[6], a[i]代表价值为i的硬币有多少.

问能否把硬币平均分为两堆.

sum(a[i]) < 5e4 (目测数据不止5e4….?保险起见开了5e5/扶额)

分析

当 sum(a[i]) 为奇数时, 必定不可分

判断体积为sum(a[i])/2的多重背包能否填满即可

设定物品价值和体积相同, 那么如果存在恰好填满的情况, 那么一定是最大价值=背包容量.

多重背包按照二进制拆分为01背包

假设价值为w的物品有n个, 则按照 1, 2, 4, 8, ….., (1^log(n)) 拆分

设sum(1, (1^log(n)) = sum, 设 ret = n - sum;

则有在 (0~sum) 内的所有数p都可以用拆分数的和表示 (二进制表示)

而(sum ~ n) 之间的数可用 p+ret表示

拆分完毕, 0-1背包构建完成.

#include <stdio.h>
#include <iostream>
#include <cstring>
using namespace std;
const int MAX = 2e5+10;
const int INF = 2e5+10;
int a[7], dp[MAX], sum, T, tmax, tmp;
int mmax(int a, int b) {
return a > b ? a : b;
}
bool getin() {
bool ret = false;
for (int i = 1; i <= 6; ++i) {
cin >> a[i];
ret |= a[i];
}
memset(dp, 0, sizeof(dp));
sum = 0;
return ret;
}
bool judge() {
for (int i = 1; i <= 6; ++i)
sum += (i*a[i]);
if (sum & 1)
return false;
sum >>= 1;
for (int i = 1; i <= 6; ++i) {
if (a[i] == 0) continue;
int k;
for (k = 1; k < a[i]; a[i] -= k, (k <<= 1))
for (int j = sum, tmp = i*k j >= tmp; --j) {
if (dp[j-tmp] + tmp > j)
continue;
dp[j] = mmax(dp[j], dp[j-tmp] + tmp);
}
for (int j = sum, tmp = a[i]*i; j >= tmp; --j) {
if (dp[j-tmp] + tmp > j)
continue;
dp[j] = mmax(dp[j], dp[j-tmp] + tmp);
}
}
if (dp[sum] == sum)
return true;
else
return false;
}
int main() {
freopen("out.t", "w", stdout);
freopen("in.t", "r", stdin);
ios::sync_with_stdio(false);
cin.tie(0);
for (T = 1; getin(); ++T) {
cout << "Collection #" << T << ":" << "\n";
if (judge())
cout << "Can be divided." << "\n\n";
else
cout << "Can't be divided." << "\n\n";
}
return 0;
}


2017-09-08
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: