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. background-size 设置背景图片的大小

    background-size 设置背景图片的大小,以长度值或百分比显示,还可以通过cover和contain来对图片进行伸缩. 语法: background-size: auto | <长度值 ...

  2. SATA SAS SSD 硬盘介绍和评测

    SATA SATA的全称是Serial Advanced Technology Attachment,是由Intel.IBM.Dell.APT.Maxtor和Seagate公司共同提出的硬盘接口规范. ...

  3. JAVA多线程学习2--线程同步

    一.线程同步介绍 同步:就是协同步调,按照预定的先后顺序执行.比如:你说完我再说. 线程同步:访问同一个共享资源的时候多个线程能够保证数据的安全性.一致性. 二.JAVA中实现线程同步的方法 实现进程 ...

  4. [大牛翻译系列]Hadoop(3)MapReduce 连接:半连接(Semi-join)

    4.1.3 半连接(Semi-join) 假设一个场景,需要连接两个很大的数据集,例如,用户日志和OLTP的用户数据.任何一个数据集都不是足够小到可以缓存在map作业的内存中.这样看来,似乎就不能使用 ...

  5. execute连接 类型

    set rs=server.createobject("adodb.recordset") sql="select top 10 id,name from tablena ...

  6. 你必须知道的.NET

    作者博客地址:http://www.cnblogs.com/anytao/archive/2008/04/09/anytao_insidenet_center.html 第1章 OO大智慧 1.1对象 ...

  7. C#中窗体的互相访问

    1.在父窗体中构造子窗体对象时,将父窗体传递过去: 如:FrmSub frm=new FrmSub(this);//this代表父窗体 2.将父窗体中要访问的变量和方法修改为public 3.在子窗体 ...

  8. 一,XAML基础

    RuntimeNameProperty特性:为什么<Grid x:Name="grid1"></Grid>等价于<Grid Name="gr ...

  9. WPF 使用定时器

    WPF 使用定时器:<ProgressBar Height="10" HorizontalAlignment="Left" Margin="28 ...

  10. apache2: bad user name ${APACHE_RUN_USER} 解决

    开工后,发现有个虚拟机的apache没起来,调用apache2 -k start 后,提示如下内容: apache2: bad user name ${APACHE_RUN_USER} apache ...