zoukankan      html  css  js  c++  java
  • 题解报告:hdu 1171 Big Event in HDU(多重背包)

    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
    解题思路:典型的多重背包问题,由于题目给的时限比较多,果断转化成01背包暴力过了233。题意是:尽量使得A,B两者分得的价值接近相等(两者价值总和为所有设施设备的总价值),并且A分得的价值不小于B分得的价值,那么问题就可以转化成不超过总价值的一半(视为背包的容量△(已经是确定值))下,挑选若干件物品装入背包后,使得总价值最大,即为B得到的最大价值,A得到的价值为sum-dp[sum/2]。最坏的时间复杂度大约为6e8级别,可见测试数据挺水的。
    AC代码一(717ms):
     1 #include<bits/stdc++.h>
     2 using namespace std;
     3 int n,v,m,num,sum,vi[5005],dp[125005];//最大价值的一半:50*100*50/2=125000,数组开大一点即可
     4 int main(){
     5     while(~scanf("%d",&n)&&n>=0){
     6         memset(vi,0,sizeof(vi));
     7         memset(dp,0,sizeof(dp));
     8         num=sum=0;//sum记录总价,num记录物品的总数
     9         while(n--){
    10             scanf("%d%d",&v,&m);
    11             while(m--){//有m个价值相等的物品
    12                 vi[num++]=v;//把m个物品看成m件不同的物品,多重背包转化成01背包
    13                 sum+=v;//累加价值
    14             }
    15         }
    16         for(int i=0;i<num;++i)
    17             for(int j=sum/2;j>=vi[i];--j)
    18                 dp[j]=max(dp[j],dp[j-vi[i]]+vi[i]);
    19         printf("%d %d
    ",sum-dp[sum/2],dp[sum/2]);//dp[sum/2]比较小即为B,因为求解过程是让max尽量靠近sum/2
    20     }
    21     return 0;
    22 }

    AC代码二(78ms):

     1 #include<bits/stdc++.h>
     2 using namespace std;
     3 int t,W,n,tol,value[55],num[55],dp[125005];
     4 void ZeroOnePack(int w,int v){//01背包
     5     for(int j=W;j>=w;--j)
     6         dp[j]=max(dp[j],dp[j-w]+v);
     7 }
     8 void CompletePack(int w,int v){//完全背包
     9     for(int j=w;j<=W;++j)
    10         dp[j]=max(dp[j],dp[j-w]+v);
    11 }
    12 void MultiplePack(int w,int v,int num){//多重背包
    13     if(w*num>=W)CompletePack(w,v);
    14     else{
    15         for(int k=1;k<=num;k<<=1){//二进制思想
    16             ZeroOnePack(w*k,v*k);
    17             num-=k;
    18         }
    19         if(num>0)ZeroOnePack(w*num,v*num);
    20     }
    21 }
    22 int main(){
    23     while(~scanf("%d",&n)&&n>=0){
    24         memset(dp,0,sizeof(dp));tol=W=0;
    25         for(int i=1;i<=n;++i){
    26             scanf("%d%d",&value[i],&num[i]);
    27             tol+=value[i]*num[i];
    28         }
    29         W=tol/2;
    30         for(int i=1;i<=n;++i)
    31             MultiplePack(value[i],value[i],num[i]);
    32         printf("%d %d
    ",tol-dp[W],dp[W]);
    33     }
    34     return 0;
    35 }

    AC代码三(62ms):单调队列优化

     1 #include<bits/stdc++.h>
     2 using namespace std;
     3 int W,n,tol,val[55],num[55],dp[125005];
     4 struct node{
     5     int k,v;
     6     node(int x,int y):k(x),v(y){}
     7 };
     8 deque<node> dq;
     9 void SingleDeque(int w,int v,int cnt){
    10     for(int r=0;r<w;++r){//r=j%w
    11         dq.clear();
    12         for(int t=0;t*w+r<=W;++t){//t=j/w
    13             int tmp=dp[t*w+r]-t*v;
    14             while(!dq.empty()&&tmp>=dq.back().v)dq.pop_back();
    15             dq.push_back(node(t,tmp));
    16             while(!dq.empty()&&(t-cnt>dq.front().k))dq.pop_front();
    17             dp[t*w+r]=dq.front().v+t*v;
    18         }
    19     }
    20 }
    21 int main(){
    22     while(~scanf("%d",&n)&&n>=0){
    23         tol=W=0;memset(dp,0,sizeof(dp));
    24         for(int i=1;i<=n;++i)
    25             scanf("%d%d",&val[i],&num[i]),tol+=val[i]*num[i];
    26         W=tol/2;
    27         for(int i=1;i<=n;i++){
    28             num[i]=min(num[i],W/val[i]);
    29             SingleDeque(val[i],val[i],num[i]);
    30         }
    31         printf("%d %d
    ",tol-dp[W],dp[W]);
    32     }
    33     return 0;
    34 }
  • 相关阅读:
    《Twinkle Twinkle Little Star》
    《牛客IOI周赛24-普及组B》
    You have to remove (or rename) that container to be able to reuse that name.
    MySQL查看服务器状态、数据库、表的命令
    【用户不在sudoers文件中】的两种解决方式
    Ubuntu20.04安装Docker时摊上的那些事儿
    Ubuntu20.04安装Docker以后设置阿里云镜像加速
    Ubuntu20.04默认更新源sources.list和第三方源推荐(干货!)
    Ubuntu必备软件之搜狗输入法
    Ubuntu20.04必备软件之截图工具
  • 原文地址:https://www.cnblogs.com/acgoto/p/9522601.html
Copyright © 2011-2022 走看看