poj 1014 Dividing 多重背包 二进制拆分

 

方法是:将第i种物品分成若干件物品,其中每件物品有一个系数,这件物品的费用和价值均是原来的费用和价值乘以这个系数。使这些系数分别为1,2,4,...,2^(k-1),n[i]-2^k+1,且k是满足n[i]-2^k+1>0的最大整数。例如,如果n[i]13,就将这种物品分成系数分别为1,2,4,6的四件物品。

其实就是拆分成所有的和加起来等于n[i];

拆分后别忘了加权,即乘以价值。

 

#include <iostream> #include <cmath> #include <cstring> using namespace std; int f[120001]; int _num[120001]; int _count; void binSplit(int k, int value) { //二进制拆分 for(int i = 0; ; i++) { int tmp = 1 << i; int next = 1 << (i + 1); if(k - next + 1 <= 0) { if(k != 0) _num[_count++] = (k - tmp + 1) * value; return; } _num[_count++] = value * tmp; } } int main() { //freopen("1.txt", "r", stdin); for(int m = 1; ; m++) { memset(_num, false, sizeof(_num)); memset(f, false, sizeof(f)); f[0] = 0; int sum = 0; _count = 0; bool ok = false; //判断是否 0 0 0 0 0 0 for(int i = 1; i <= 6; i++) { int k; cin >> k; binSplit(k, i); sum += i * k; if(k != 0) ok = true; } if(!ok) break; cout << "Collection #" << m << ":/n"; if(sum % 2 != 0) { cout << "Can't be divided./n/n"; continue; } ok = false; //判断是否能划分成功 sum /= 2; for(int i = 0; i < _count && !ok; i++) { for(int j = sum; j >= _num[i]; j--) { if(j == f[j - _num[i]] + _num[i]) { if(j == sum) { ok = true; break; } f[j] = f[j - _num[i]] + _num[i]; } } } if(ok) cout << "Can be divided./n/n"; else cout << "Can't be divided./n/n"; } return 0; } 

你可能感兴趣的:(poj 1014 Dividing 多重背包 二进制拆分)