【CJWYH】RHL的背包题解(多重背包)
2015-08-04 16:06
211 查看
题面
【问题描述】
CJ中学组织学生出去春游,作为学神的RHL自然不会放过这一大好时机,他有n种物品,第i件物品有c[i]个,每个体积为v[i],价值为w[i],RHL现在有一个体积为V的背包,他想让他带的东西价值之和最大,且体积之和不超过V,你能帮帮他吗?注意物体不能分割。【输入】
输入文件名为bag.in,分为若干行。第一行包含两个正整数n,V。第二行到第n+1行分别描述第i种物品的数量c[i],体积v[i],价值w[i]
【输出】
输出文件名为bag.out,一行输出一个整数,表示最大价值。【输入输出样例】
bag.in5 50
1 1 7
2 1 4
2 4 1
3 1 3
2 3 8
bag.out
42
【数据说明】
30%的数据满足n<=5,<=10,V<=100;50%的数据满足n<=100,<=1000,V<=1000;
100%的数据满足n<=100,1<=c[i]<=10^5,1<=v[i]<=V<=10^4,1<=w[i]<=10^9
题解
方法1
分析
多重背包,数据很水,全是随机,DP裸过代码
#include<iostream> #include<stdio.h> #include<stdlib.h> #include<math.h> #include<string.h> #include<algorithm> using namespace std; long long f[10000001]={0},n,V,v[1001],w[1001],c[1001]; int main() { freopen("bag.in","r",stdin); freopen("bag.out","w",stdout); cin>>n>>V; for (int i=1;i<=n;i++) cin>>c[i]>>w[i]>>v[i]; for (int i=1;i<=n;i++) for (int j=V;j>=w[i];j--) for (int k=0;k<=min(c[i],j/w[i]);k++) f[j]=max(f[j-k*w[i]]+k*v[i],f[j]); cout<<f[V]; return 0; }
方法2
分析
如果出题人有意卡的话——如所有物品体积为1,有很多个,背包容积很大
这个算法会爆
于是做优化处理
我们考虑1<=c[i]<=10^5
转换成二进制数在17位以内
我们可以把c[i]件物品拆分成最多17件,
按二进制位拆分
如15143个物品/(11101100100111)2(11101100100111)_2拆成
(10000000000000)2=8192(10000000000000)_2=8192
(1000000000000)2=4096(1000000000000)_2=4096
(100000000000)2=2048(100000000000)_2=2048
(1000000000)2=512(1000000000)_2=512
(100000000)2=256(100000000)_2=256
(100000)2=32(100000)_2=32
(100)2=4(100)_2=4
(10)2=2(10)_2=2
(1)2=1(1)_2=1
合起来正好为15143个
这样就转化为了01背包
复杂度O(NVlog2c[i])O(NVlog_2c[i])
代码
#include<iostream> #include<cstdio> #include<cstring> #include<cstdlib> #include<cmath> #include<algorithm> #define N 105 #define M 2505 #define MaxV 10005 #define LL long long #define oo (1<<30) #ifdef WIN32 #define TAT "%I64d" #else #define TAT "%lld" #endif using namespace std; LL f[MaxV],wm[M],ans=0; int n,m,V,c ,v ,w ,vm[M]; int main() { int i,j; freopen("bag.in","r",stdin); freopen("bag.out","w",stdout); scanf("%d %d",&n,&V); for(i=1;i<=n;i++){ scanf("%d %d %d",&c[i],&v[i],&w[i]); for(j=1;(j<<1)<=c[i];j<<=1) vm[++m]=j*v[i],wm[m]=1LL*j*w[i]; vm[++m]=(c[i]-j+1)*v[i]; wm[m]=1LL*(c[i]-j+1)*w[i]; } for(i=1;i<=m;i++) for(j=V;j>=vm[i];j--) f[j]=max(f[j],f[j-vm[i]]+wm[i]); for(i=0;i<=V;i++) ans=max(ans,f[i]); printf(TAT,ans); return 0; }
PS:RHL=R64=2013级的湖南OI界老大哥
相关文章推荐
- 《程序员面试宝典》--栈和堆,局部变量和全局变量
- iOS App上架AppStore 会遇到的坑
- 使用Mybatis 如何显示sql 语句?
- php处理http post/get请求
- IOS学习之UITableView(三):进阶篇索引,标记和自定义的table
- Linux下Weblogic 11g R1安装和配置
- java web实现分页显示数据
- poj 2187 旋转卡壳(平面上最远点对)
- Amdahl定律
- c++中异常类的使用方法
- Mysql对检索结果进行处理后返回以及在列上使用函数
- IOS中UIActionSheet使用详解
- ubuntu+qt5.5安装完错误
- 搜索引擎-倒排索引基础知识
- Git基本慨念
- Cookie/Session机制详解(转)
- lib dev dbg doc
- 让您的电脑在任意目录可以支持图片的粘贴,试试看呗~
- 在Cocos2d-x中实现较为真实的云彩效果
- 输入整数m,k将会出现大于m的k个与m最近的连续素数