HDU 1711 Big Event in HDU(01背包+多重背包)

Time Limit:5000MS Memory Limit:32768KB 64bit IO Format: %I64d & %I64u

 Status

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

        大致题意就是杭电在很久以前计算机院是分为两个院系的,牵扯到分东西的问题,一个相同的东西可能有多个,两个院系必须要平均,不能把一个东西拆成分散开,必须是一整个。如果实在是不能平分,那就让先输出多的。

        解题思路:可以当做一个多重背包来做,利用一个一维的数组,把每个数相加可以构成的数在数组中标记(如10和20相加=30,用掉了一个20,就把dp[30]标记成20剩下的个数,dp[30]=1)。也可以简单处理,看成一个01背包。先算出总价值的一半,用一半作为背包容量,看最多能装多少,这就转化为01背包了。在转为01背包的时候录入的时候需要预处理,同时记得把数组开大一点。

       这道题给的时间也比较长5000Ms,我提交了一下两个方法,01背包的形式时间在1000Ms左右,而多重背包的接近0Ms,两者的空间复杂度差不多,只是多重背包比较优化一些。虽然多重背包不好懂 ,但是更推荐多重背包。

       01背包code:

#include<stdio.h>
#include<string.h>
#include<iostream>
using namespace std;
int dp[255000],v[5000];
int main()
{
    int i,j,n,m,a,b;
    while(~scanf("%d",&n))
    {
        if(n<0)  break;
        int sum=0,l=0;
        for(i=0; i<n; i++)
        {
            scanf("%d%d",&a,&b);
            sum+=a*b;
            while(b--)
            {
                v[l++]=a;
            }
        }
        int k=sum/2,s=0;
        memset(dp,0,sizeof(dp));
        for(i=0; i<l; i++)
            for(j=k; j>=v[i]; j--)
            {
                dp[j]=max(dp[j],dp[j-v[i]]+v[i]);
            }
        printf("%d %d\n",sum-dp[k],dp[k]);
    }
    return 0;
}

     多重背包code:

#include<stdio.h>
#include<string.h>
#include<iostream>
using namespace std;
int dp[255000],v[100],w[100];
int main()
{
    int i,j,n,m;
    while(~scanf("%d",&n))
    {
        if(n<0)  break;
        int sum=0;
        for(i=0; i<n; i++)
        {
            scanf("%d%d",&v[i],&w[i]);
            sum+=v[i]*w[i];//算出总价值
        }
        int k=sum/2,s=0;//一半作为背包容量
        memset(dp,-1,sizeof(dp));
        dp[0]=0;
        for(i=0; i<n; i++)
        {
            for(j=0; j<=k; j++)
            {
                if(dp[j]>=0)//表示j这个数在上一次的时候就可以组成。
                    dp[j]=w[i];
                else if(j<v[i]||dp[j-v[i]]<=0)//无法通过各个数组合构成j。
                    dp[j]=-1;
                else dp[j]=dp[j-v[i]]-1;//上一次没有组成j这个数,需要用到这次的数,就把他的个数减去1.
            }
        }
        for(i=k; i>=0; i--)
        {
            if(dp[i]>=0)
            {
                 s=i;
                break;
            }
        }

        printf("%d %d\n",sum-s,s);
    }
    return 0;
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值