01背包

有N件物品和一个容量为V的背包。第i件物品的费用(即体积,下同)是w[i],价值是c[i]。求解将哪些物品装入背包可使这些物品的费用总和不超过背包容量,且价值总和最大。

基本思路:   

  这是最基础的背包问题,特点是:每种物品仅有一件,可以选择放或不放。   

  用子问题定义状态:即f[i][v]表示前i件物品(部分或全部)恰放入一个容量为v的背包可以获得的最大价值。

  则其状态转移方程便是:f[i][v]=max{f[i-1][v],f[i-1][v-w[i]]+c[i]}。   

  这个方程非常重要,基本上所有跟背包相关的问题的方程都是由它衍生出来的。

  所以有必要将它详细解释一下:“将前i件物品放入容量为v的背包中”这个子问题,若只考虑第i件物品的策略(放或不放),那么就可以转化为一个只牵扯前i-1件物品的问题。如果不放第i件物品,那么问题就转化为“前i-1件物品放入容量为v的背包中”;如果放第i件物品,那么问题就转化为“前i-1件物品放入剩下的容量为v-w[i]的背包中”,此时能获得的最大价值就是f [i-1][v-w[i]]再加上通过放入第i件物品获得的价值c[i]。

  注意f[i][v]有意义当且仅当存在一个前i件物品的子集,其费用总和为v。所以按照这个方程递推完毕后,最终的答案并不一定是f[N][V],而是f[N][0..V]的最大值。如果将状态的定义中的“恰”字去掉,在转移方程中就要再加入一项f[i-1][v],这样就可以保证f[N][V]就是最后的答案。

  但是若将所有f[i][j]的初始值都赋为0,你会发现f[n][v]也会是最后的答案。  

  因为这样你默认了最开始f[i][j]是有意义的,只是价值为0,就看作是无物品放的背包价值都为0,所以对最终价值无影响,这样初始化后的状态表示就可以把“恰”字去掉。

e.g.

【问题描述】 一个旅行者有一个最多能用m公斤的背包,现在有n件物品,它们的重量分别是W1,W2,...,Wn,它们的价值分别为C1,C2,...,Cn.若每种物品只有一件求旅行者能获得最大总价值。

【输入格式】 第一行:两个整数,M(背包容量,M<=200)和N(物品数量,N<=30); 第2..N+1行:每行二个整数Wi,Ci,表示每个物品的重量和价值。

【输出格式】 仅一行,一个数,表示最大总价值。

【样例输入】10 4 2 1 3 3 4 5 7 9

【样例输出】12

#include<cstdio>
using namespace std;
const int maxm = , maxn = ;
int m, n;
int w[maxn], c[maxn];
int f[maxn][maxm]; int max(int x,int y) { x>y?x:y;} //求x和y最大值 int main(){
scanf("%d%d",&m, &n); //背包容量m和物品数量n
for (int i = ; i <= n; i++) //在初始化循环变量部分,定义一个变量并初始化
scanf("%d%d",&w[i],&c[i]); //每个物品的重量和价值
for (int i = ; i <= n; i++) // f[i][v]表示前i件物品,总重量不超过v的最优价值
for (int v = m; v > ; v--)
if (w[i] <= v) f[i][v] = max(f[i-][v],f[i-][v-w[i]]+c[i]);
else f[i][v] = f[i-][v];
printf("%d",f[n][m]); // f[n][m]为最优解
return ;
}

【解法一】设f[i][v]表示前i件物品,总重量不超过v的最优价值,则f[i][v]=max(f[i-1][v-w[i]]+c[i],f[i-1][v]) ;f[n][m]即为最优解

 #include<cstdio>
using namespace std; const int maxm = , maxn = ;
int m, n;
int w[maxn], c[maxn];
int f[maxm];
int main(){
scanf("%d%d",&m, &n); //背包容量m和物品数量n
for (int i=; i <= n; i++)
scanf("%d%d",&w[i],&c[i]); //每个物品的重量和价值 for (int i=; i <= n; i++) //设f(v)表示重量不超过v公斤的最大价值
for (int v = m; v >= w[i]; v--)
if (f[v-w[i]]+c[i]>f[v])
f[v] = f[v-w[i]]+c[i];
printf("%d",f[m]); // f(m)为最优解
return ;
}

【解法二】本问题的数学模型如下:设 f[v]表示重量不超过v公斤的最大价值, 则f[v]=max{f[v],f[v-w[i]]+c[i]} ,当v>=w[i],1<=i<=n


完全背包问题

有N种物品和一个容量为V的背包,每种物品都有无限件可用。第i种物品的费用是w[i],价值是c[i]。求解将哪些物品装入背包可使这些物品的费用总和不超过背包容量,且价值总和最大。

  这个问题非常类似于01背包问题,所不同的是每种物品有无限件。也就是从每种物品的角度考虑,与它相关的策略已并非取或不取两种,而是有取0件、取1件、取2件……等很多种。如果仍然按照解01背包时的思路,令f[i][v]表示前i种物品恰放入一个容量为v的背包的最大权值。仍然可以按照每种物品不同的策略写出状态转移方程,

像这样将01背包问题的基本思路加以改进:f[i][v]=max{f[i-1][v-k*w[i]]+k*c[i]|0<=k*w[i]<= v}   

这个算法使用一维数组,伪代码:   for i=1..N    for v=0..V      f[v]=max{f[v],f[v-w[i]]+c[i]};

  这个伪代码与01背包问题的伪代码只有v的循环次序不同而已。首先想想为什么01背包问题中要按照v=V..0的逆序来循环。这是因为要保证第i次循环中的状态f[i][v]是由状态f[i-1][v-w[i]]递推而来。

  换句话说,这正是为了保证每件物品只选一次,保证在考虑“选入第i件物品”这件策略时,依据的是一个绝无已经选入第i件物品的子结果f[i-1][v-w[i]]。而现在完全背包的特点恰是每种物品可选无限件,所以在考虑“加选一件第i种物品”这种策略时,却正需要一个可能已选入第i种物品的子结果f[i][v-w[i]],所以就可以并且必须采用v= 0..V的顺序循环。这就是这个简单的程序为何成立的道理。   

  这个算法也可以以另外的思路得出。例如,基本思路中的状态转移方程可以等价地变形成这种形式:f[i][v]=max{f[i-1][v],f[i][v-w[i]]+c[i]},将这个方程用一维数组实现,便得到了上面的伪代码。

e.g.

【问题描述】   设有n种物品,每种物品有一个重量及一个价值。但每种物品的数量是无限的,同时有一个背包,最大载重量为M,今从n种物品中选取若干件(同一种物品可以多次选取),使其重量的和小于等于M,而价值的和为最大。

【输入格式】 第一行:两个整数,M(背包容量,M<=200)和N(物品数量,N<=30); 第2..N+1行:每行二个整数Wi,Ci,表示每个物品的重量和价值。

【输出格式】 仅一行,一个数,表示最大总价值。

【样例输入】 10 4 2 1 3 3 4 5 7 9

【样例输出】max=12

 #include<cstdio>
using namespace std; const int maxm = , maxn = ;
int m, n;
int w[maxn], c[maxn];
int f[maxn][maxm];
int main()
{
scanf("%d%d",&m, &n); //背包容量m和物品数量n
for (int i = ; i <= n; i++)
scanf(“%d%d”,&w[i],&c[i]); //每个物品的重量和价值
for (int i = ; i <= n; i++) //f[i][v]表示前i件物品,总重量不超过v的最优价值
for (int v = ; v <= m; v++)
if (v < w[i]) f[i][v] = f[i-][v];
else
        if (f[i-][v] > f[i][v-w[i]]+c[i]) f[i][v] = f[i-][v];
else f[i][v] = f[i][v-w[i]]+c[i];
printf("max=%d",f[n][m]); // f[n][m]为最优解
return ;
}

【解法一】 设f[i][v]表示前i件物品,总重量不超过v的最优价值,则f[i][v]=max(f[i][v-w[i]]+c[i],f[i-1][v]) ;f[n][m]即为最优解。

DP方程及意义的更多相关文章

  1. uvalive 5721 Activation (概率dp+方程)

    题目链接:http://vjudge.net/problem/viewProblem.action?id=24999 主要思想就是解方程的思想. 二维dp应该很容易想到,就是当前位置加队伍长度. dp ...

  2. dp方程

    1.        资源问题1 -----机器分配问题 F[I,j]:=max(f[i-1,k]+w[i,j-k]) 2.        资源问题2 ------01背包问题   F[I,j]:=ma ...

  3. zoj-3329-期望/dp/方程优化

    One Person Game Time Limit: 1 Second      Memory Limit: 32768 KB      Special Judge There is a very ...

  4. 洛谷P1140 基因匹配 //DP真正意义上的一血

    题目背景 大家都知道,基因可以看作一个碱基对序列.它包含了44种核苷酸,简记作A,C,G,TA,C,G,T.生物学家正致力于寻找人类基因的功能,以利用于诊断疾病和发明药物. 在一个人类基因工作组的任务 ...

  5. 【BZOJ-1096】仓库建设 斜率优化DP

    1096: [ZJOI2007]仓库建设 Time Limit: 10 Sec  Memory Limit: 162 MBSubmit: 3719  Solved: 1633[Submit][Stat ...

  6. hdu1114Piggy-Bank(DP完全背包)

    题意:在ACM可以做任何事情,必须准备和预算获得必要的财政支持.这次行动的主要收入来自不可逆绑定金钱(IBM).背后的想法很简单.每当一些ACM成员有任何小的钱,他把所有的硬币和成小猪银行抛出.你知道 ...

  7. HDU3045 Picnic Cows (斜率DP优化)(数形结合)

    转自PomeCat: "DP的斜率优化--对不必要的状态量进行抛弃,对不优的状态量进行搁置,使得在常数时间内找到最优解成为可能.斜率优化依靠的是数形结合的思想,通过将每个阶段和状态的答案反映 ...

  8. dp之背包总结篇

    //新手DP学习中 = =!! 前言:背包问题在dp中可以说是经典,作为一个acmer,到现在才正式学习dp,可以说是比较失败的.我个人比较认同一点,想要做一个比较成功的acmer,dp.搜索.数学必 ...

  9. Codeforces1101F Trucks and Cities 【滑动窗口】【区间DP】

    题目分析: 2500的题目为什么我想了这么久... 考虑答案是什么.对于一辆从$s$到$t$的车,它有$k$次加油的机会.可以发现实际上是将$s$到$t$的路径以城市为端点最多划分为最大长度最小的$k ...

随机推荐

  1. if语句代码优化

    if($sum==7){ $sz+=135; }elseif($sum==5){ $sz+=80; }elseif($sum==6){ $sz+=97; }elseif($sum==4){ $sz+= ...

  2. JQ中的html()、text()、val()的用法

    <input type="text" val=""> 用val(); <sapn>你好</sapn>  用text() &l ...

  3. NSS_06 extjs弹出窗口上的文本框默认获得焦点

    这个问题其实是个窗户纸, 没什么技术含量,但是做的过程中有点曲折, 所以也记录下来吧. Ext.window.Window中有focus(o1, o2)方法, 作用:Try to focus this ...

  4. Linux下iftop网卡流量监控使用

    在类linux系统中可以使用top查看系统资源.进程.内存占用等信息.查看网络状态可以使用netstat.nmap等工具.若要查看实时的网络流量,监控TCP/IP连接等,则可以使用iftop. 一.i ...

  5. IOS_修改项目模板

    1. /Applications/Xcode.app/Contents/Developer/Library/Xcode/Templates/File\ Templates/Source/Cocoa\ ...

  6. 如何查看 Apache 的版本

    查看 Apache 服务器版本的命令行为: httpd -v 或者 apachectl -v 例如:用 Xshell 连接到服务器后,输入:httpd -v 或者:apachectl -v 返回: S ...

  7. SQL JOB

    数据库同步是一种比较常用的功能.以下结合我自己的体会整理的,如果有理解不完全或者有误的地方望大牛不理赐教.下面介绍的就是数据库同步的两种方式: 1.SQL JOB的方式 sql Job的方式同步数据库 ...

  8. openerp - asterisk connector(转载)

    原文:http://www.akretion.com/open-source-contributions/openerp-asterisk-voip-connector OpenERP - Aster ...

  9. find命令小结

    find命令小结 find命令用于在系统中查找文件,配合 -exec 选项或 xargs命令还能对查找到得文件执行一些列的自动化操作. 基本格式:find [-H] [-L] [-P] [path.. ...

  10. GOOGLE影像地图

    卫星地图高清 //