POJ 1014 dividing

分析:

如果想要公平的分得弹球,那么弹球的价值总和一定是偶数,可以先进行判断弹球的价值总和,若是奇数则不需要做下面的判断。

如果是偶数,我们可以把这个问题映射为多重背包问题,并且这个背包是要求完全装满的。背包的总容量V就是所有弹球总价值和sum的一半,弹球的cost和weight都是其编号。个数则是由外界输入的。最后进行判断:如果得到的F[V]确定的等于sum/2,则说明能够公平的分弹球。

需要注意的是,由于弹球最大个数是20000,所以极端情况是20000个弹球都是放在了价值为6的位置上,这样,V的最大值就是6*20000/2+1=60001。

好了,翠花,上代码:

#include <iostream>
using namespace std;

#define LEN 7
#define INIT 0xffffffff
int F[60001];

int max(int x, int y)
{
	return x>y?x:y;
}

void ZeroOnePack(int cost, int weight, int V)
{
	for (int v=V; v>=cost; --v) {
		F[v] = max(F[v], F[v-cost]+weight);
	}
}

void CompletePack(int cost, int weight, int V)
{
	for (int v=cost; v<=V; ++v) {
		F[v] = max(F[v], F[v-cost]+weight);
	}
}

void MultiPack(int cost, int weight, int V, int amount)
{
	if (cost*amount>=V) {
		CompletePack(cost, weight, V);
		return;
	}
	int k = 1;
	while (k<amount) {
		ZeroOnePack(cost*k, weight*k, V);
		amount -= k;
		k *=2;
	}
	ZeroOnePack(cost*amount, weight*amount, V);
}

int main(int argc, char **argv)
{
	int index = 0;
	int num[LEN];
	while (1) {
		++index;
		int sum = 0;
		int bin = 0;
		for (int i=1; i<LEN; ++i) {
			cin>>num[i];
			sum += i * num[i];
			bin |= num[i];
		}
		if (!bin)
			break;
		if (sum&0x01)
			cout<<"Collection #"<<index<<":\n"<<"Can't be divided."<<endl<<endl;
		else {
			int V = sum>>1;
			F[0] = 0;
			for (int i=1; i<=V; ++i)
				F[i] = INIT;
			for (int i=1; i<LEN; ++i)
				MultiPack(i, i, V, num[i]);
			if(F[V]!=V)
				cout<<"Collection #"<<index<<":\n"<<"Can't be divided."<<endl<<endl;
			else
				cout<<"Collection #"<<index<<":\n"<<"Can be divided."<<endl<<endl;
		}
	}
	system("pause");
	return 0;
}

0MS过!done!


你可能感兴趣的:(poj)