背包问题
应用场景
给定 $n$ 种物品和一个背包。物品 $i$ 的重量是 $w_i$ ,其价值为 $v_i$ ,背包的容量为C。应该如何选择装入背包中的物品,使得装入背包的总价值最大?
*01 背包

*01 背包特点:
  给定 $n$ 种物品和一个背包 ( 每个物品只能选取一个)。物品$i$ 的重量是$w[i]$,其价值为$v[i]$,背包的容量为C。应该如何选择装入背包中的物品,使得装入背包中的物品的总价值最大?
*状态:
  $dp[i][j]$ 表示在只能从 $1-i$ 个物品中选择物品并且背包容量大小为 $j$ 的情况下,所能获得的最大价值。
*限制条件
  • 只能选择物品 1 ~ i
  • 选择物品的总重量不能超过 $j$
*状态转移方程:
  $dp[i][j] = max(dp[i-1][j], dp[i-1][j-w[i]] + v[i])$;

*实现:

1)初始化:

 int n,m; //n表示物品个数,m表示背包容量
for (int i = ;i<= m ;i++)
dp[][i] = ;

2)-1二维数组实现:

 for (int i = ;i <= n ;i++){
for (int j = ;j<=m ;j++){
dp[i][j] = dp[i-][j];
if (j-w[i]>=)
dp[i][j] = max(dp[i][j],dp[i-][j-w[i]]+v[i]);
}
}

2)-2一维数组实现

 for (int i = ;i <= n ;i++){
for (int j = m ;j>= ;j--){
if (j-w[i]>=)
dp[j] = max(dp[j],dp[j-w[i]]+v[i]);
}
}

*完全背包

*完全背包特点

  给定 $n$ 种物品和一个背包 ( 每个物品选取无限个)。物品 $i$ 的重量是 $w[i]$,其价值为$v[i]$,背包的容量为$C$。应该如何选择装入背包的物品,是的装入背包中物品的总价值最大?
*状态

  $dp[i][j]$ 表示在只能从 $1-i$ 个物品中选择物品并且背包容量大小为 $j$ 的情况下,所能获得的最大价值。
*限制条件

  • 只能选择物品 1 ~ i
  • 选择物品的总重量不能超过 j

*状态转移方程

  $dp[i][j] = max(dp[i-1][j], dp[i][j-w[i]] + v[i])$;

*实现

1)初始化

 int n,m; //n表示物品个数,m表示背包容量
for (int i = ;i<= m ;i++)
dp[][i] = ;

2)-1二维数组实现

 for (int i =;i <= n;i++){
for (int j = ;j <= m;j++){
dp[i][j]=dp[i-][j];
if (w[i]<=j)
dp[i][j]=max(dp[i][j],dp[i][j-w[i]]+v[i]);
}
}

2)-2一维数组实现

 for (int i =;i <= n;i++){
for (int j = ;j <= m;j++){
if (d-w[i]>=)
dp[j]=max(dp[j],dp[j-w[i]]+v[i]);
}
}

*多重背包

*多重背包特点

  给定 $n$ 种物品和一个背包 ( 每个物品选取有限个)。物品 $i$ 的重量是 $w[i]$ ,其价值为$v[i]$,每个物品可以取$k[i]$个,背包的容量为C。应该如何选择装入背包中的物品使得装入背包中的物品总价值最大?

*状态

  $dp[i][j]$ 表示在只能从 $1-i$ 个物品中选择物品并且背包容量大小为 $j$ 的情况下,所能获得的最大价值

*限制条件

  • 只能选择物品 1 ~ i
  • 选择物品的总重量不能超过 j

*状态转移

  $dp[i][j] = max(dp[i-1][j], dp[i-1][j-w[i]] + v[i], dp[i-1][j-w[i]*2] + v[i]*2,...)$

*实现

1)初始化

2)-1二维数组实现

 for (int i = ;i <= n ;i++){
for (int j = ;j<=m ;j++){
dp[i][j] = dp[i-][j];
for (int z = ; z<=k[i]; z++)
if (j-w[i]*z>=)
dp[i][j] = max(dp[i][j],dp[i-][j-z*w[i]]+z*v[i]);
else
break;
}
}

2)-2一维数组实现

 for (int i = ;i <= n ;i++){
for (int j = m ;j>= ;j--){
for (int z = ; z<=k[i] ;z++)
if (j-w[i]*z>=)
dp[j] = max(dp[j],dp[j-z*w[i]]+z*v[i]);
else
break;
}
}

*多重背包问题转化为 01 背包问题
1. p 以下的数字可否由若干不同数字通过组合得到
  (a) $2^n$- 1 $n$ == 7 二进制: 111111 000001、000010、000100、001000、010000、100000
  (b) $k$ + $2^n$ -1 < $2^{n+1}$ -1 $n$ == 7
• $2^n$ -1 及以下的数字可以由以下数字表示 000001、000010、000100、001000、010000、100000
• 大于 $2^n$ -1 的数字 $k$ 加上以上 7 个数字组成的数字可以表示任何大于$2^n$ - 1小于等于k+$2^n$-1的数字
2. 代码实现

 //num[i] 表示第i种硬币可以取多少次
//w[j] 表示转后为01背包后 只能取一次的硬币的价值与重量
int totlW = ;
memset(w,,sizeof w);
for (int i = ;i< ; i ++){
for(int j=; j<=num[i]; j<<=){
w[totlW++]=j*(i+);
num[i]-=j;
}
if(num[i]>)
w[totlW++]=num[i]*(i+);
}

背包问题
HDU 2602
POJ 2063
POJ 1787
UVA 674
UVA 147

第一题是01背包的板子题,就直接放代码了:

 #include <iostream>
#include <cstdio>
#include <algorithm>
#include <cmath>
#include <cstring>
using namespace std;
int t;
int n,m;
int val[],w[],f[];
int main ()
{
scanf ("%d",&t);
while (t--)
{
scanf ("%d%d",&n,&m);
memset(f,,sizeof(f));
for (int i = ;i <= n;i++)
scanf ("%d",&val[i]);
for (int i = ;i <= n;i++)
scanf ("%d",&w[i]);
for (int i = ;i <= n;i++)
for (int j = m;j >= w[i];j--)
f[j]=max(f[j],f[j-w[i]]+val[i]);
printf ("%d\n",f[m]);
}
return ;
}

第二道题是完全背包,因为每个债券都是1000的倍数,所以我们可以直接把总钱数和债券的数额都直接除以1000.因为每年都会有利息,所以每年的总钱数会增加,求出每一年的最大利益,总钱数加上最大利益就是下一年的总钱数。所以,我们只需要对于每一年的总钱数求一个完全背包,每年更新总钱数就好。代码如下:

 #include <iostream>
#include <cstdio>
#include <algorithm>
#include <cmath>
#include <cstring>
using namespace std;
const int N = ;
int dp[N];
int num[N], val[N];
int main()
{
int t;
scanf("%d", &t);
while(t--)
{
int money,year,d;
scanf("%d %d", &money, &year);
scanf("%d", &d);
for(int i=;i<d;i++)
{
scanf("%d %d", &num[i], &val[i]);
num[i]/=;
}
int sum=money;
for(int i=;i<year;i++)
{
memset(dp,,sizeof(dp));
money=sum;
money/=;
for(int j=;j<d;j++)
{
for(int k=num[j];k<=money;k++)
{
dp[k]=max(dp[k-num[j]]+val[j],dp[k]);
}
}
sum+=dp[money];
}
printf("%d\n",sum);
}
return ;
}

第三题是完全背包+路径输出,$dp[j]$表示总价格为$j$时最多可以有多少个硬币,但是需要维护一下硬币的个数,实际上在01背包中,我们对所有状态都更新了一次答案,这里我们等于是对4种硬币各跑一次背包,维护一下使用次数即可。$used[j]$表示总价格为j时用了多少个某个硬币。$pre[j]$记录方案,表示j出现更有的答案时是由哪个状态转移来的。最后遍历一下输出答案就好了。

 #include <stdio.h>
#include <string.h>
using namespace std;
int dp[], used[], pre[], coin[] = {, , , }, num[], ans[];
int main(){
int p;
while(scanf("%d %d %d %d %d", &p, &num[], &num[], &num[], &num[]) != EOF){
if(p + num[] + num[] + num[] + num[] == ) return ;
for(int i = ; i <= p; ++i){
dp[i] = -1e9;
}
memset(pre, , sizeof(pre));
pre[] = -;
dp[] = ;
for(int i = ; i < ; ++i){
memset(used, , sizeof(used));
for(int j = coin[i]; j <= p; ++j){
if(dp[j] < dp[j - coin[i]] + && used[j - coin[i]] < num[i]){
used[j] = used[j - coin[i]] + ;
dp[j] = dp[j - coin[i]] + ;
pre[j] = j - coin[i];
}
}
}
if(dp[p] <= ){
printf("Charlie cannot buy coffee.\n");
continue;
}
memset(ans, , sizeof(ans));
while(){
if(pre[p] == -) break;
ans[p - pre[p]]++;
p = pre[p];
}
printf("Throw in %d cents, %d nickels, %d dimes, and %d quarters.\n", ans[], ans[], ans[], ans[]);
}
}

第四题一个简单的动态规划,比如要求55的组成方案数,必须要知道55-1=54的方案数 和 55-5=50的方案数,和50-10=45的方案数和55-25=30的方案数和55-50=5的方案数,所以dp以此类推,每次更新dp。

 #include <cstring>
#include <iostream>
#include <cstdio>
using namespace std;
int f[];
int main ()
{
int v;
while(cin>>v){
memset(f,,sizeof(f));
int c[]={,,,,,};
f[]=;
for(int i = ; i <= ; ++i)
for(int j = c[i]; j <= v; ++j)
{
f[j] = f[j]+f[j-c[i]];
}
cout << f[v]<<endl;
}
return ;
}

专题复习--背包问题+例题(HDU 2602 、POJ 2063、 POJ 1787、 UVA 674 、UVA 147)的更多相关文章

  1. HDU 2602 Bone Collector (01背包问题)

    原题代号:HDU 2602 原题链接:http://acm.hdu.edu.cn/showproblem.php?pid=2602 原题描述: Problem Description Many yea ...

  2. HDU 2602 Bone Collector 0/1背包

    题目链接:pid=2602">HDU 2602 Bone Collector Bone Collector Time Limit: 2000/1000 MS (Java/Others) ...

  3. POJ 2063 Investment (完全背包)

    A - Investment Time Limit:1000MS     Memory Limit:30000KB     64bit IO Format:%I64d & %I64u Subm ...

  4. poj 2063 Investment ( zoj 2224 Investment ) 完全背包

    传送门: POJ:http://poj.org/problem?id=2063 ZOJ:http://acm.zju.edu.cn/onlinejudge/showProblem.do?problem ...

  5. POJ 2289 Jamie's Contact Groups / UVA 1345 Jamie's Contact Groups / ZOJ 2399 Jamie's Contact Groups / HDU 1699 Jamie's Contact Groups / SCU 1996 Jamie's Contact Groups (二分,二分图匹配)

    POJ 2289 Jamie's Contact Groups / UVA 1345 Jamie's Contact Groups / ZOJ 2399 Jamie's Contact Groups ...

  6. HDOJ(HDU).2602 Bone Collector (DP 01背包)

    HDOJ(HDU).2602 Bone Collector (DP 01背包) 题意分析 01背包的裸题 #include <iostream> #include <cstdio&g ...

  7. 倍增&矩阵乘法 专题复习

    倍增&矩阵乘法 专题复习 PreWords 这两个基础算法我就不多说啦,但是还是要介绍一下" 广义矩阵 "乘法 其实就是把矩阵换成取\(max\),然后都一样... 据神仙 ...

  8. 状压dp专题复习

    状压dp专题复习 (有些题过于水,我直接跳了) 技巧总结 : 1.矩阵状压上一行的选择情况 \(n * 2^n\) D [BZOJ2734][HNOI2012]集合选数 蒻得不行的我觉得这是一道比较难 ...

  9. POJ 1496 POJ 1850 组合计数

    Code Time Limit: 1000MS Memory Limit: 30000K Total Submissions: 8256 Accepted: 3906 Description Tran ...

随机推荐

  1. 前端学习笔记系列一:1.export default / export const

    export default 是默认导出 export const 是命名导出 参考:Javascript (ES6), export const vs export default(基本上就是翻译这 ...

  2. 0. GC 前置知识

    阅读<垃圾回收的算法与实现>时记录的一些笔记. 对象 在GC的世界中,对象表示的是"通过应用程序利用的数据的集合" 头 我们将对象中保存对象本身信息的部分称为头.头主要 ...

  3. vb.net导出CSV文件

    Public Function WriteToCSV(ByVal dataTable As DataTable, ByVal filePath As String, ByVal records As ...

  4. 修改Centos7的yum源

    以下为修改Centos7的yum源: 1. 备份原镜像文件,便于后期恢复 [root@keepmydream ~]# mv /etc/yum.repos.d/CentOS-Base.repo /etc ...

  5. Java笔记--异常

    1.异常分为两类: --1)Error:Java虚拟机无法解决的严重问题(例如资源耗尽等): --2)Exception:其他编程错误或偶然的外在因素导致的一般性问题(例如空指针异常.读取的文件不存在 ...

  6. ASP.NETCore -----导入Excel文件

    前端上传excel文件利用npoi读取数据转换成datatable(netcore坑爹啊,用的vs2017竟然不能可视化) 前端界面 @{ Layout = null; } <!DOCTYPE ...

  7. LeetCode559 N叉树的最大深度

    题目: 思路: 直接递归求解最大深度就可以,这里主要记录一下Java中比较获得两个数中最大值的方法. import java.math.*; class Solution { public int m ...

  8. 小程序 scroll-view 中文字不换行问题

    问题描述:在scroll-view 中scroll-x="true"时控制文字超出显示省略号,要求如图: 但实际中会出现如文字不换行或样式错乱的问题. 横向滚动的实现如下: 超过两 ...

  9. Python3中的bytes和str类型

    Python 3最重要的新特性之一是对字符串和二进制数据流做了明确的区分.文本总是Unicode,由str类型表示,二进制数据则由bytes类型表示.Python 3不会以任意隐式的方式混用str和b ...

  10. ExcelPackage导入导出,命名空间一定要是EPPlus

    1.引入EPPlus.dll,旧版的是OfficeOpenXml.dll,最好使用EPPlus2.调用 string path = UploadExecl(batchUpload.BinaryExce ...