杭电1171————DP之01背包

Big Event in HDU

Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)
Total Submission(s): 22939    Accepted Submission(s): 8058


Problem Description
Nowadays, we all know that Computer College is the biggest department in HDU. But, maybe you don't know that Computer College had ever been split into Computer College and Software College in 2002.
The splitting is absolutely a big event in HDU! At the same time, it is a trouble thing too. All facilities must go halves. First, all facilities are assessed, and two facilities are thought to be same if they have the same value. It is assumed that there is N (0<N<1000) kinds of facilities (different value, different kinds).
 

Input
Input contains multiple test cases. Each test case starts with a number N (0 < N <= 50 -- the total number of different facilities). The next N lines contain an integer V (0<V<=50 --value of facility) and an integer M (0<M<=100 --corresponding number of the facilities) each. You can assume that all V are different.
A test case starting with a negative integer terminates input and this test case is not to be processed.
 

Output
For each case, print one line containing two integers A and B which denote the value of Computer College and Software College will get respectively. A and B should be as equal as possible. At the same time, you should guarantee that A is not less than B.
 

Sample Input
2 10 1 20 1 3 10 1 20 2 30 1 -1
 

Sample Output
20 10 40 40
题目中有一个比较特殊的限制条件就是A和B要尽量相等,那么可以求出所有物品的maxvalue之后均分当做背包的容量。
并且A >= B 则dp[i]表示i容量下A所能获得的最大容量。
值得注意的是,maxvalue /2 很可能是一个小数,例如若maxvalue = 35 则 maxvalue / 2 == 17 比实际所希望的数值(17.5—— >18)要小,那么dp[maxvalue / 2]是偏小的那个值(因为背包容量小),也就是B而不是A.
第一种方法(杭电亲测500MS左右 数据范围太大了)
#include <stdio.h>
#include <string.h>
#define max(A,B) ((A) > (B) ? (A) : (B))

int dp[255555];/*dp[i]表示前i件物品分到computer学院最大价值*/
/*从题目的表述中 种类最大1000单价最大100个数最大50那么maxvalue / 2 为2500000*/ 
int value[5005];
/*value[i]表示第i件物品的价值*/ 
/*由上方注释知最多5000个物品*/ 

int main()
{
	int single_value;/*单位物品的价值*/
	int number;/*物品的数量*/
    int n;/*物品的种类*/
	
	while(scanf("%d",&n) != EOF & n >= 0)
	{
		int maxvalue = 0;/*总价值*/ 
		int sum = 0;/*物品总数*/ 
		memset(dp,0,sizeof(dp));
		memset(value,0,sizeof(value));
		for(int i = 0 ; i < n ; i++)
		{
			scanf("%d%d",&single_value,&number);
			while(number--)
			{
				value[sum++] = single_value;
				maxvalue += single_value;
			}
		}
		/*对于第i件物品,有两种状态,分给computer学院或者分给soft学院,抽象为01背包*/
		/*因为要求两方尽量相等则computer学院的背包容量为 maxvalue / 2*/ 
		for(int i = 0; i < sum ; i++)
		{
			for(int j = maxvalue / 2 ; j >= value[i] ; j--)
				dp[j] = max(dp[j],dp[j-value[i]] + value[i]);
		}
		printf("%d %d\n",maxvalue - dp[maxvalue /2 ],dp[maxvalue / 2]);
	} 
	return 0;
}
第二种方法(非DP 杭电亲测0MS........别人的方法...)
思路大致是这样的:
将value按照升序排序,把大的值优先分给A,如果说A的值+value[i]超过了 maxvalue /2 则不加这个值 继续+value[i-1],否则就加value[i]
value数组全部遍历一遍即得答案
<pre name="code" class="cpp">#include <iostream>
#include <string.h>
#include <algorithm>
using namespace std;
const int MAX = 110000;
int a[MAX],len,n;
int main()
{
    while(cin >> n && n >= 0){
        memset(a,0,sizeof(a));
        int num,value,sum = 0;
        len = 0;
        for(int i=0;i<n;i++){
            cin >> value >> num;
            sum += value * num;
            while(num--)
                a[len++] = value;
        }
        sort(a,a+len);
        int half = sum / 2;
        num = 0;
        for(int i=len-1;i>=0;i--){
            if(num + a[i] > half)
                continue;
            num += a[i];
        }
        cout << sum - num << " " << num << endl;
    }
    return 0;
}



posted @ 2014-07-30 15:39  SixDayCoder  阅读(185)  评论(0编辑  收藏  举报