01背包问题
假设你是一名经验丰富的探险家,背着背包来到野外进行日常探险。天气晴朗而不燥热,山间的风夹杂着花香,正当你欣赏这世外桃源般的美景时,突然,你发现了一个洞穴,这个洞穴外表看起来其貌不扬,但凭借着惊为天人的直觉,这个洞穴不简单。于是,你开始往洞穴内探索,希望能发现一些有意思的东西。终于,皇天不负有心人,你在洞穴的尽头,发现了一堆珠宝,凭借你惊人的阅历,一眼便看出了它们各自的价值,心想着下下下下下下下下半辈子都有着落了。然而,天有不测风云,正准备将它们收入囊中,却不小心触碰到一个防御机关,洞穴马上就要崩塌了。在此危机时刻,你只有一个背包,你必须尽快做出抉择,从中选择最值钱的珠宝塞到你的背包,让背包中珠宝的总价值最大。好了好了,啰里啰嗦了大半天,我还是来精简一下问题吧。简而言之,你只有一个容量有限的背包,总容量为c,有n个可待选择的物品,每个物品只有一件,它们都有各自的重量和价值,你需要从中选择合适的组合来使得你背包中的物品总价值最大。问题分析:那还不简单,不管是什么,先往背包里塞,塞满赶紧走,狗命要紧,狗命要紧。。。好了好了,开个玩笑,言归正传。简单起见,我们来将上面的问题具体化,举一个更具体的栗子:假设有4个物品,它们的价值(v)和重量(w)如下图:
背包总容量为10,现在要从中选择物品装入背包中,要求物品的重量不能超过背包的容量,并且最后放在背包中物品的总价值最大。emmm,等等,为什么叫做0/1背包呢?为什么不叫1/2背包,2/3背包???仔细想想,这里每个物品只有一个,对于每个物品而言,只有两种选择,盘它或者不盘,盘它记为1,不盘记为0,我们不能将物品进行分割,比如只拿半个是不允许的。这就是这个问题被称为0/1背包问题的原因。所以究竟选还是不选,这是个问题。让我们先来体验一下将珠宝装入背包的感觉,为了方便起见,用xi代表第i个珠宝的选择(xi = 1 代表选择该珠宝,0则代表不选),vi代表第i个珠宝的价值,wi代表第i个珠宝的重量。于是我们就有了这样的限制条件:
我们的初始状态是背包容量为10,背包内物品总价值为0,接下来,我们就要开始做选择了。对于1号珠宝,当前容量为10,容纳它的重量2绰绰有余,因此有两种选择,选它或者不选。我们选择一个珠宝的时候,背包的容量会减少,但是里面的物品总价值会增加。就像下面这样:
这样就分出了两种情况,我们继续进行选择,如果我们选择了珠宝1,那么对于珠宝2,当前剩余容量为8,大于珠宝2的容量3,因此也有两种选择,选或者不选。
现在,我们得到了四个可能结果,我们每做出一个选择,就会将上面的每一种可能分裂成两种可能,后续的选择也是如此,最终,我们会得到如下的一张决策图:
这里被涂上色的方框代表我们的最终待选结果,本来应该有16个待选结果,但有三个结果由于容量不足以容纳下最后一个珠宝,所以就没有继续进行裂变。然后,我们从这些结果中,找出价值最大的那个,也就是13,这就是我们的最优选择,根据这个选择,依次找到它的所有路径,便可以知道该选哪几个珠宝,最终结果是:珠宝4,珠宝2,珠宝1。简单的看,对于每个物品,无外乎两种可能:选,或者不选。不选的话,背包的容量不变,最大价值还是之前的价值;选的话,背包的容量变小,价值变大。最优方案就是比较这两种方案,哪个会更好些:
**
01背包问题
[算法分析]
定义状态∶dp[i][j]:有i件物品,背包容量为j的情况下存储的最大价值w[i]第i件物品的重量,c背包总容量,j表示背包实时容量,也就是0到c之间的容量,v[i]第i件物品的价值如果w[i]>j:放不下,最大价值为i-1件物品讨论时的最大价值,即dp[i-1][j];如果w[i]<=j:放得下:
选上: 剩余容量:j-w[i],最大价值:v[i] + (i-1件物品,容量在j- w[i]的情况下最大价值),即v[i]+dp[i-1][j-w[i]];不选: 最大价值:i-1件物品讨论时的最大价值,即dp[i-1][j];所以动态转移方程:dp[i][j]=max(dp[i-1][j],v[i]+dp[i-1][j-w[i]])
```cpp
#include<bits/stdc++.h>
using namespace std;
/*
动态转移方程:dp[i][j]=max(dp[i-1][j],v[i]+dp[i-1][j-w[i]])
*/
//c代表背包容量
//dp[i][j]:有i件物品,背包容量为j的情况下存储的最大价值
int c,dp[40][210],w[40],v[40],i,j,n;
int main(){
cin >> c>>n;
for(i=1;i<=n;i++){
cin >> w[i]>>v[i];
}
//递推求dp数组
for(i=1;i<=n;i++){
//在i件物品,讨论背包容量j分别是1-c的情况下,最大价值
//j代表背包容量
for(j=1;j<=c;j++){
//如果能够放得下
if(w[i]<=j){
dp[i][j]=max(dp[i-1][j],v[i]+dp[i-1][j-w[i]]);
} else{
//放不下
dp[i][j]=dp[i-1][j];
}
}
}
cout << dp[n][c];
return 0;
}
背包
有个背包可承受重量N,现有T件物品,每件物品重量为wi,价值为vi,每件物品只有一个,这个背包可以装载物品的最大价值是多少?输入格式第一行,两个整数,分别表示N和T,用空格隔开(N≤1000,T≤100)接下来T行,每行两个整数,分别表示T件物品的重量wi和价值vi(1≤wi,vi≤100)输出格式一行,表示这个背包可以装载物品的最大价值输入输出样列
输入样例1:
100 577 9222 2229 8750 4699 90
输出样例1:
133
[算法分析]定义状态∶d(i,j)表示为前i个物品分配j容量的背包,可以获得的最大价值。对于物品i有2种选择∶选择1∶ 不选择将i放入背包∶ d(i, j) = d(i-1,j)。选择2∶选择将i放入背包d(i,j)=d(i-1,j-wi)+vi(j>=wi)。状态转移方程∶ d(i,j)= max(d(i-1,j), d(i-1,j-wi)+vi)。
#include<bits/stdc++.h>
using namespace std;
const int N=1005,T=105;
//dp[i][j]:有i件物品,背包容量为j的情况下存储的最大价值
int dp[T][N],v[T],w[T];
int main()
{
int n,t;
cin>>n>>t;
for(int i=1;i<=t;i++)
{
cin>>w[i]>>v[i];
}
for(int i=1;i<=t;i++) //t件物品
{
for(int j=1;j<=n;j++)
//在i件物品,讨论背包容量j分别是1-n的情况下,最大价值
//j代表背包容量
{
if(j>=w[i])//放得下
dp[i][j]=max(dp[i-1][j],v[i]+dp[i-1][j-w[i]]);
else//放不下
dp[i][j]=dp[i-1][j];
}
}
cout<<dp[t][n];
return 0;
}
————未完
一定拖更
我
好了,背包问题(1·)就到这——别走第二期动态规划下期更新!!!o( ̄▽ ̄)d
播放量到150下期继续
不见不散