poj 1014 分宝物 多重背包

类似于 1276

题意:给定若干个宝物,价值为1-6,每个宝物数量不一,能否均分成两个

解法:

统计总价值total,首先必须是偶数,然后总价值i * num(i)其中 (i= 1-6) 

然后total / 2作为背包的体积,每个物品的价值作为体积,也作为价值,类似于poj 1276

但是,注意这个题的要求不一样,一定要拼出来最终答案

即滚动数组f[V] == V才可以,这跟要求f[V]最大不一样,具体不一样的地方在于初始化的时候

要求恰好装满背包,那么在初始化时除了f[0]为0其它f[1..V]均设为-∞

这样就可以保证最终得到的f[N]是一种恰好装满背包的最优解。


注意初始化的上下界是 [0----V]  WA了一次

另外题目中说 最多的数目为 20000 那么V 最大为 20000*6  / 2 =60000

maxn 设置数组开的不够大导致 RA一次

都是通过测试数据发现的问题,囧。。。

测试输入

1 0 1 2 0 0
1 0 0 0 1 1
2 0 0 3 0 0
1 1 1 1 1 1
0 6999 0 6001 0 7000
0 0 0 0 4 5
3333 3333 3333 3333 3333 3333
0 0 0 1 0 2
1 2 3 4 5 6
0 0 0 0 4 5
0 0 2 3 0 0
0 0 0 2 2 1
0 0 0 1 2 2
0 1 2 3 4 5
6 5 4 3 2 1
0 0 5 0 3 0
0 3 0 0 0 1
0 2 0 1 0 0
1 1 1 0 0 0
3334 3334 3333 3333 3333 3333
0 1 1 1 1 1
0 0 0 0 6 5
0 0 0 3 0 2
0 0 1 3 3 4
0 0 0 1 4 6
0 0 0 1 4 5
0 0 0 0 0 0
测试输出

 

Collection #1:
Can't be divided.

Collection #2:
Can be divided.

Collection #3:
Can't be divided.

Collection #4:
Can't be divided.

Collection #5:
Can't be divided.

Collection #6:
Can't be divided.

Collection #7:
Can't be divided.

Collection #8:
Can't be divided.

Collection #9:
Can't be divided.

Collection #10:
Can't be divided.

Collection #11:
Can't be divided.

Collection #12:
Can't be divided.

Collection #13:
Can't be divided.

Collection #14:
Can be divided.

Collection #15:
Can be divided.

Collection #16:
Can be divided.

Collection #17:
Can be divided.

Collection #18:
Can be divided.

Collection #19:
Can be divided.

Collection #20:
Can be divided.

Collection #21:
Can be divided.

Collection #22:
Can be divided.

Collection #23:
Can be divided.

Collection #24:
Can be divided.

Collection #25:
Can be divided.

Collection #26:
Can be divided.


代码:

#include <iostream>
#include <vector>
#include <map>
#include <list>
#include <set>
#include <deque>
#include <stack>
#include <queue>
#include <algorithm>
#include <cmath>
#include <cctype>
#include <cstdio>
#include <iomanip>
#include <cmath>
#include <cstdio>
#include <iostream>
#include <string>
#include <sstream>
#include <cstring>
#include <queue>
using namespace std;

///宏定义
const int  INF = 990000000;
const int maxn = 150000 ;
const int MAXN = maxn;
///全局变量 和 函数
int max(int a, int b)
{
	return a > b ? a : b;
}

int N;
int V;
//int mnums[maxn];
//int mval[maxn];
int fee[maxn];
int nums[10];
int f[maxn];
int main()
{
	///变量定义
	int i, j, m;
	int cases = 1;
	while(1)
	{
		int totval = 0;
		int V;
		bool flag = false;
		for (i = 1; i <= 6; i++)
		{
			scanf("%d", &nums[i]);
			if (nums[i] != 0)
			{
				flag = true;
				totval += i * nums[i];
			}			
		}
		if (!flag)
			break;
		printf("Collection #%d:\n", cases++);
		if (totval % 2 != 0)
		{
			printf("Can't be divided.\n");
			printf("\n");
			continue;
		}
		else
			V = totval / 2;
		
		int cnt = 0;
		for (int kk = 1; kk <= 6; kk++) //进行分组,存入fee数组
		{
			if (nums[kk] == 0)
				continue;
			int k = 0;
			int temp = 1;
			while (1)
			{
				if (temp - 1 >= nums[kk])
					break;
				temp *= 2;
				k++;
			}
			k = k - 1;
			
			//分组
			int at = 1;
			for (i = 0; i < k + 1; i++)
			{
				
				if (i != 0)
				{
					if (i == k)
					{
						at = nums[kk] - at * 2 + 1;
					}
					else
						at *= 2;
				}
				fee[cnt++] = at * kk;
			}
		}
		
		//		memset(f, 0, sizeof(f));
		//初始化f数组
		for (i = 0; i <= V; i++) //初始化不正确WA一次,通过测试数据发现  
			                     //V上限可能超过 maxn RA一次,通过测试数据发现,对于f的访问越界改变了fee数组的值
								 // 数目最多20000个,所以值的上限可能很大
		{
			if (i == 0)
			{
				f[i] = 0;
			}
			else
				f[i] = -INF;
		}
		//0-1背包经典求解
		for (i = 0; i < cnt; i++)
		{
			for (j = V; j >= 0; j--)
			{
				if (j >= fee[i])
				{
					if (f[j - fee[i]] == -INF)
						continue;
					if (f[j] < f[j - fee[i]] + fee[i])
					{
						f[j] = f[j - fee[i]] + fee[i];
					}
				}
			}
		}
		
		int ans = f[V];
		if (ans == V)
		{
			printf("Can be divided.\n");
			printf("\n");
		}
		else
		{
			printf("Can't be divided.\n");
			printf("\n");
		}
		//		printf("%d\n", ans);
	}
	
	///结束
	return 0;
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值