[POJ - 1014] Dividing (多重背包)

链接

http://poj.org/problem?id=1014

题意

给你价值分别为 1 、 2 、 3 、 4 、 5 、 6 1、2、3、4、5、6 123456的大理石 n 1 、 n 2 、 n 3 、 n 4 、 n 5 、 n 6 n_1、n_2、n_3、n_4、n_5、n_6 n1n2n3n4n5n6份,数量和不超过 20000 20000 20000,现在问是否能把大理石分成价值相同的两份;

分析

  这一题和 p o j 1742 poj1742 poj1742很像,首先考虑特殊情况,如果大理石价值总和为奇数,无论如何都不能分成相同两份,对于偶数的情况考虑多重背包;即第 i i i种物品有 n i n_i ni个,价值为 i i i,每个物品可以选多次;
  
  这时候背包的容量为价值总和 s u m sum sum也行,为 s u m / 2 sum/2 sum/2也可以,在第 i i i阶段, d p [ j ] dp[j] dp[j]表示前 i i i种硬币是否能拼成价值 j j j(所以它只有两种可能,要么为0要么为1,并且 d p [ 0 ] = 1 dp[0]=1 dp[0]=1),我这里使用了二进制拆分将其转化为一个 01 01 01背包(不优化不知道能不能过),最后的时候看 d p [ s u m / 2 ] dp[sum/2] dp[sum/2]是否为1即可,需要注意的是这里没有类似求最大价值等最优问题,而是一个可行性问题;

代码
#include <functional>
#include <algorithm>
#include <iostream>
#include <cstring>
#include <string>
#include <cstdio>
#include <vector>
#include <queue>
#include <stack>
#include <cmath>
#include <set>
#include <map>

#define INF 0x7f7f7f7f
#define MAXN 100005
#define N 200005
#define P 2
#define MOD 99991

typedef long long ll;

namespace fastIO {
	//#define getchar() (p1 == p2 && (p2 = (p1 = buf) + fread(buf, 1, 1<<22, stdin), p1 == p2) ? EOF : *p1++)
	//char buf[(1 << 22)], *p1 = buf, *p2 = buf;
	inline int read() {
		char c = getchar(); int x = 0, f = 1;
		while (c < '0' || c > '9') { if (c == '-') f = -1; c = getchar(); }
		while (c >= '0' && c <= '9') x = x * 10 + c - '0', c = getchar();
		return x * f;
	}
}

using namespace fastIO;
using namespace std;

int a[8], dp[5 * MAXN], cnt;
int main() {
	while (cin >> a[1] >> a[2] >> a[3] >> a[4] >> a[5] >> a[6]) {
		int sum = 0;
		for (int i = 1; i <= 6; i++)
			sum += a[i] * i;
		if (sum == 0)break;
		printf("Collection #%d:\n", ++cnt);
		if (sum % 2) {
			printf("Can't be divided.\n\n");
			continue;
		}
		memset(dp, 0, sizeof(dp));
		dp[0] = 1;
		for (int i = 1; i <= 6; i++) {
			if (!a[i])continue;
			int num = min(a[i],sum / i);
			for (int j = 1; num > 0; j <<= 1) {
				if (j > num)j = num;
				num -= j;
				for (int k = sum; k >= j * i; k--)
					dp[k] |= dp[k - j * i];
			}
		}
		if (dp[sum / 2])
			cout << "Can be divided.\n" << endl;
		else cout << "Can't be divided.\n" << endl;
	}
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值