HDU 1171 Big Event in HDU (多重背包,可转换为01背包)+对于背包的一点认识 4000
2017-10-09 20:28
465 查看
传送门:HDU 1171
题目大意:有n(n<=50)种东西,告诉你每种东西的价值val(val<=50)和数量num(num<=100),现在要你把这些东西分为两组,使得两组的价值总和之差尽量小。求两组的价值和,大者在前。
前置技能:我默认读这篇文章的读者已经了解过了01背包、完全背包和多重背包了。如果没有也没关系,给推荐个网站:背包九讲。
再来稍微谈下多重背包的思路,当一种物品的数量足够多,以至于总重量比背包的容量都大的话,相当于这种物品的数量有无穷多个,这时候可以转化为完全背包求解。
相反,当一种物品的数量不够多的时候,可以把这一堆同样的物品拆分成多个单个的物品,这时候就可以用01背包求解了。但是呢,这样拆分的话复杂度太高了,所以有另一种方式,我称之为倍增法,先拆出1个,如果剩下的还能拆再拆出2个(这2个看作是一个物品),如果剩下的还能拆再拆出4个(这4个看作是一个物品)……依次类推拆出2的次幂个。如果不够了,那么剩下的就是一个物品。
例如有13个某种物品,先拆出1个,还剩12个,再拆出2个,剩余10个,再拆出4个,剩余6个,再拆出8个,发现不够了,所以剩下的6个看作一个物品。这样本来13个物品被拆成了4个物品,时间复杂度大大降低。
思路:我们假设物品总价值为sum,我们发现,最优的情况是两个分组各占一半,稍差一点的情况是一者不到一半,另一者比一半多。所以我们就可以看看一个容量为 sum/2 的背包能装多满。因为每个物品有固定的数量,这就是多重背包问题。有人可能会说,这里只有价值,没有背包的容量啊,其实题目做多了你可以发现,只有一个值的时候价值和重量是可以共用的。
下面提供两种思路:
转换为01背包问题:01背包就是有n种东西,要么取,要么不取,因为最多一共有50*100=5000件物品,所以可以把每个价值相同的物品拆成单个物品,然后用01背包求解。这种思路简单,代码也少,但是时间复杂度高,如果数据再大点就不适用了。
直接用多重背包解决:也就是用所有的物品往一个容量为 sum/2 的背包里装,装到最满顶多一半,这时候的值就是少者的值。
上图上面的是用01背包思路做的,下面的是用多重背包思路做的,可以发现用多重背包要快很多,当然了,代码会稍微多点,不过直接套模板就可以了。
注意:输入时当n<0时退出,也不可以写成 n==-1 时退出,否则会答案错误或者超时。
先给出01背包的代码:
然后是多重背包的代码,上面的部分可以直接用作模板,我测试过个3版本的多重背包,下面这个是最快的。当然还可能存在更快的也未可知……
题目大意:有n(n<=50)种东西,告诉你每种东西的价值val(val<=50)和数量num(num<=100),现在要你把这些东西分为两组,使得两组的价值总和之差尽量小。求两组的价值和,大者在前。
前置技能:我默认读这篇文章的读者已经了解过了01背包、完全背包和多重背包了。如果没有也没关系,给推荐个网站:背包九讲。
再来稍微谈下多重背包的思路,当一种物品的数量足够多,以至于总重量比背包的容量都大的话,相当于这种物品的数量有无穷多个,这时候可以转化为完全背包求解。
相反,当一种物品的数量不够多的时候,可以把这一堆同样的物品拆分成多个单个的物品,这时候就可以用01背包求解了。但是呢,这样拆分的话复杂度太高了,所以有另一种方式,我称之为倍增法,先拆出1个,如果剩下的还能拆再拆出2个(这2个看作是一个物品),如果剩下的还能拆再拆出4个(这4个看作是一个物品)……依次类推拆出2的次幂个。如果不够了,那么剩下的就是一个物品。
例如有13个某种物品,先拆出1个,还剩12个,再拆出2个,剩余10个,再拆出4个,剩余6个,再拆出8个,发现不够了,所以剩下的6个看作一个物品。这样本来13个物品被拆成了4个物品,时间复杂度大大降低。
思路:我们假设物品总价值为sum,我们发现,最优的情况是两个分组各占一半,稍差一点的情况是一者不到一半,另一者比一半多。所以我们就可以看看一个容量为 sum/2 的背包能装多满。因为每个物品有固定的数量,这就是多重背包问题。有人可能会说,这里只有价值,没有背包的容量啊,其实题目做多了你可以发现,只有一个值的时候价值和重量是可以共用的。
下面提供两种思路:
转换为01背包问题:01背包就是有n种东西,要么取,要么不取,因为最多一共有50*100=5000件物品,所以可以把每个价值相同的物品拆成单个物品,然后用01背包求解。这种思路简单,代码也少,但是时间复杂度高,如果数据再大点就不适用了。
直接用多重背包解决:也就是用所有的物品往一个容量为 sum/2 的背包里装,装到最满顶多一半,这时候的值就是少者的值。
上图上面的是用01背包思路做的,下面的是用多重背包思路做的,可以发现用多重背包要快很多,当然了,代码会稍微多点,不过直接套模板就可以了。
注意:输入时当n<0时退出,也不可以写成 n==-1 时退出,否则会答案错误或者超时。
先给出01背包的代码:
#include<stdio.h> #include<string.h> int val[5010],dp[250010]; int max(int a,int b) { if(a>b) return a; else return b; } int main() { int i,j,n,a,b,v,sum,tol; while(~scanf("%d",&n)&&n>=0) { tol=0; //下标 sum=0; //总价值 for(i=1;i<=n;i++) { scanf("%d%d",&a,&b); sum+=a*b; while(b--) val[tol++]=a; //拆成单个 } v=sum/2; //一半的容量 memset(dp,0,sizeof(dp)); //01背包核心代码 for(i=0;i<tol;i++) for(j=v;j>=val[i];j--) dp[j]=max(dp[j],dp[j-val[i]]+val[i]); printf("%d %d\n",sum-dp[v],dp[v]); } return 0; }
然后是多重背包的代码,上面的部分可以直接用作模板,我测试过个3版本的多重背包,下面这个是最快的。当然还可能存在更快的也未可知……
#include<stdio.h> #include<string.h> int n,v,dp[250010]; int max(int a,int b) { if(a>b) return a; else return b; } //01背包,当前物品价格、重量 void ZOP(int prz,int wt) { int j; for(j=v;j>=wt;j--) dp[j]=max(dp[j],dp[j-wt]+prz); } //完全背包,当前物品价格、重量 void CP(int prz,int wt) { int j; for(j=wt;j<=v;j++) dp[j]=max(dp[j],dp[j-wt]+prz); } //多重背包,当前物品价格、重量、数量 void MP(int prz,int wt,int cnt) { //如果放不下全部,则转化为完全背包求解 if(wt*cnt>=v) CP(prz,wt); else //否则,转化为01背包求解 { //将cnt个相同物品分多组,每组1,2,4,8…个 //类似于倍增法,最后剩下的可能不是2的次幂 int k=1; while(k<cnt) { //k个物品的价值和重量分别为 k*prz,k*wt ZOP(k*prz,k*wt); cnt-=k; k<<=1; } if(cnt>0) ZOP(cnt*prz,cnt*wt); } } int main() { int i,sum,val[55],num[55]; while(~scanf("%d",&n)&&n>=0) { sum=0; //总价值 for(i=1;i<=n;i++) { scanf("%d%d",&val[i],&num[i]); sum+=val[i]*num[i]; } v=sum/2; //一半的体积 memset(dp,0,sizeof(dp)); //多重背包求解 for(i=1;i<=n;i++) MP(val[i],val[i],num[i]); printf("%d %d\n",sum-dp[v],dp[v]); } return 0; }
相关文章推荐
- HDU1171--Big Event in HDU--01背包,多重背包
- HDU/HDOJ 1171 Big Event in HDU 01背包、多重背包、母函数
- HDU 1171 Big Event in HDU (多重bool背包) /(01背包)
- hdu 1171 Big Event in HDU(多重背包转化为01背包)
- hdu 1171 Big Event in HDU (01背包)
- Hdu 1171 Big Event in HDU (多重背包)
- HDU - 1171 Big Event in HDU(多重背包或BFS)
- hdu 1171 Big Event in HDU(母函数|多重背包)
- HDOJ 1171 Big Event in HDU (多重背包) / (母函数)
- HDU 1171.Big Event in HDU【01背包】【5月26】
- HDU-1171-Big Event in HDU(01背包的简单变形)
- hdu——1171——Big Event in HDU(多重背包)
- HDU--航但--1171--Big Event in HDU--01背包
- [HDOJ 1171] Big Event in HDU 【完全背包】
- HDU 1171 Big Event in HDU (多重背包)
- HDU 1171 Big Event in HDU(01背包)
- HDU 1171 Big Event in HDU 多重背包
- HDU 1171 Big Event in HDU(多重背包)
- hdoj1171 Big Event in HDU(01背包 || 多重背包)
- HDU 1171 Big Event in HDU 多重背包 .