背包总结
2015-11-04 17:04
274 查看
有n种物品和一个容量为v 的背包。第i种物品最多有Mi (Mi=1,k,INF)(01,完全,多重)件可用,每件耗费的空间是Ci,价值是Wi。求解将哪些物品装入背包可使这些物品的耗费的空间总和不超过背包容量,且价值总和最大。
背包初始化:
恰好装满:dp[0]=0,dp[1~n]= - INF;(负无穷)
不必装满:dp[0~n]=0;
1.01背包
2.完全背包
3.
多重背包
二进制分解 O(N*&Mi) (&Mi为M1+M2+……Mn)
单调队列 O(NV):
详见:多重背包讲解
4.二维背包
4.分组背包
详见: 《背包九讲》
背包初始化:
恰好装满:dp[0]=0,dp[1~n]= - INF;(负无穷)
不必装满:dp[0~n]=0;
1.01背包
for(int i=1;i<=n;i++) for(int j=v;j>=c[i];j--) dp[j]=max(dp[j-c[i]]+w[i],dp[j]);
2.完全背包
for(int i=1;i<=n;i++) for(int j=c[i];j<=v;j++) dp[j]=max(dp[j-c[i]]+w[i],dp[j]);
3.
多重背包
二进制分解 O(N*&Mi) (&Mi为M1+M2+……Mn)
void ZeroOnePack(int cost,int wei)//01 { int i; for(i = v;i>=cost;i--) { dp[i] = max(dp[i],dp[i-cost]+wei); } } void CompletePack(int cost,int wei)//完全 { int i; for(i = cost;i<=v;i++) { dp[i] = max(dp[i],dp[i-cost]+wei); } } void MultiplePack(int cost,int wei,int cnt)//多重 { if(v<=cnt*cost)//如果总容量比这个物品的容量要小,那么这个物品可以直到取完,相当于完全背包 { CompletePack(cost,wei); return ; } else//否则就将多重背包转化为01背包 { int k = 1; while(k<=cnt) { ZeroOnePack(k*cost,k*wei); cnt = cnt-k; k = 2*k; } ZeroOnePack(cnt*cost,cnt*wei); } }
单调队列 O(NV):
详见:多重背包讲解
const int MAX_V = 100004; //v、n、w:当前所处理的这类物品的体积、个数、价值 //V:背包体积, MAX_V:背包的体积上限值 //f[i]:体积为i的背包装前几种物品,能达到的价值上限。 inline void pack(int f[], int V, int v, int n, int w) { if (n == 0 || v == 0) return; if (n == 1) { //01背包 for (int i = V; i >= v; --i) if (f[i] < f[i - v] + w) f[i] = f[i - v] + w; return; } if (n * v >= V - v + 1) { //完全背包(n >= V / v) for (int i = v; i <= V; ++i) if (f[i] < f[i - v] + w) f[i] = f[i - v] + w; return; } int va[MAX_V], vb[MAX_V]; //va/vb: 主/辅助队列 for (int j = 0; j < v; ++j) { //多重背包 int *pb = va, *pe = va - 1; //pb/pe分别指向队列首/末元素 int *qb = vb, *qe = vb - 1; //qb/qe分别指向辅助队列首/末元素 for (int k = j, i = 0; k <= V; k += v, ++i) { if (pe == pb + n) { //若队列大小达到指定值,第一个元素X出队。 if (*pb == *qb) ++qb; //若辅助队列第一个元素等于X,该元素也出队。 ++pb; } int tt = f[k] - i * w; *++pe = tt; //元素X进队 //删除辅助队列所有小于X的元素,qb到qe单调递减,也可以用二分法 while (qe >= qb && *qe < tt) --qe; *++qe = tt; //元素X也存放入辅助队列 f[k] = *qb + i * w; //辅助队列首元素恒为指定队列所有元素的最大值 } } }
4.二维背包
for(int i=0;i<k;i++) { for(int v=value[i][1];v<=m;v++) { for(int b=1;b<=s;b++) { dp[v][b]=dp[v][b]>dp[v-value[i][1]][b-1]+value[i][0]?dp[v][b]:dp[v-value[i][1]][b-1]+value[i][0]; if(dp[v][b]>=n&&m-v>=cost) { cost=m-v; } } } } if(dp[m][s]<n)printf("-1\n"); else printf("%d\n",cost); }
4.分组背包
for(int i=1;i<=N;i++) for(int j=V;j>=0;j--) for(int k=1;k<=j;k++) f[j]=max(f[j],f[j-k]+A[i][k]);
详见: 《背包九讲》
相关文章推荐
- Android自定义View(4)
- MyBatis注意事项二
- media query 代码实例
- List存储Java对象
- 有三个桶,两个大的可装8斤的水,一个小的可装3斤的水,现在有16斤水装满了两大桶就是8斤的桶,小桶空着,如何把这16斤水分给4个人,每人4斤。没有其他任何工具,4人自备容器,分出去的水不可再要回来。
- 【ios开发】关于NSPredicate的详解
- Java关键字this、super使用总结
- 组织数据结构的能力
- 全面分析Java的垃圾回收机制
- WSDL 不可访问,无法解析
- Java并发编程实践 -- Executor框架
- 第 1 部分 从输出流中读取
- 迷宫游戏 堆栈实现
- 接口与继承动手动脑整理
- 《ArcGIS Runtime SDK for Android开发笔记》——(8)、关于ArcGIS Android开发的未来(“Quartz”版Beta)
- js原生设计模式——2面向对象编程之闭包2
- 虚拟机网卡详解
- 一个不错的下载年鉴的网站
- 深度优先搜索与广度优先搜索
- Android自定义View(3)