信息笔记——动态规划之基础(5)------背包问题总结

本人由于水平有限,笔记难免有疏漏与不严谨的地方,请大家给予批评指正,谢谢! 

对不起各位,我的信息笔记——动态规划之基础(4)------最长上升子序列续集并没有保存,所以这里并没有上传。不过,我会重新上传的,谢谢大家!!

一、0-1背包

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

主体思路就在0-1中了,我们先不考虑这些。

分析一下:

由于每一种背包只有一个,所以我们无论是从头开始,还是从尾部开始考虑这个问题结果都一样。

那么,我们开始分析这个问题。对于一个背包,我们只有两种选择(0-1):选(1)还是不选(0)。

如果我们选了这一个背包,那么我们的总价值就是我们现有的价值加上这个背包的价值,但同时,我们的空间就会少一个这个背包的空间;如果不选,我们和以前一样。

举个例子来说:现在你的背包容量还剩5,现有的价值为1,这里有一个背包需占3个单位的容量,价值是6。

如果我们选择了这个背包,我们剩余容量为2,我们总价值是7;不选,我们还是和以前一样。

那如果剩余容量小于背包的空间,怎么办?

直接跳过,不去选择这个背包。

好,我们定义状态:

每一种背包只有一个,这就意味着我们必须要有顺序的构建状态,或者说,是把顺序当作状态的一种要素,定义状态。

假设我们定义d(i)为看这个背包及以前的背包所得最优的价值,那么d(i)又等于什么呢?不知道。换句话说,定义的状态不好,导致转移困难。

那么好像我们的状态定义的有问题,缺了某点要素。

我们再回想一下:如果我们选了这一个背包,那么我们的总价值就是我们现有的价值加上这个背包的价值,但同时,我们的空间就会少一个这个背包的空间。

我们的状态中缺少的是剩余容量这一要素。

好,我们定义d(i,j)为第i个背包在容量为j时所装的最优价值。

如果选了这个背包,那么所得价值:   d(i-1,j-w(i))+c(i);

如果不选,那么所得价值就是上一个所得的价值:   d(i-1,j);

所以,两者较大的一个为我们的最优解:d(i,j)=max{ d(i-1,j),d(i-1,j-w(i))+c(i)};

于是,仿照最优三角路线,我们可以得出递归代码:

#include<cstdio>
#include<iostream>
using namespace std;
int max(int a,int b){return b>a?b:a;}
int w[110]= {},c[110]={},dp[110][1010]= {};
int bf(int t,int m) {
    if(m==0)return 0;
    if(dp[m][t]>0)return dp[m][t];
    return dp[m][t]=w[m]<=t?max(bf(t,m-1),c[m]+bf(t-w[m],m-1)):bf(t,m-1);
}
int main() {
    int m,t;
    cin>>t>>m;
    for(int i=1; i<=m; i++)cin>>w[i]>>c[i];
    cout<<bf(t,m)<<endl;
    return 0;
}

关于递推,我在开始接触的时候始终不明白,为什么一定要像填一个表一样for循环。

为了解决这个疑惑,我们设有n个背包,背包容量是m。

那么,d(n,m)就是我们想要的答案。

d(n,m)依靠着比较d(n-1,m)和d(n-1,m-w(i))+c(i);

而它们两个状态,依赖于更前面得出的状态。

所以得到d(n,m)相对于得到将前面所有的状态。

所以用填表法可以解决。

如果不明白的自己列一个表,看看。

所以递推代码就很好解决了(细节多,要注意)。

#include<iostream>
#include<cstdio>
using namespace std;
int w[100+10]= {},c[100+10]= {},d[100+10][2000];
int max(int a,int b){return a>b?a:b;}
int main() {
    int t,m;
    cin>>t>>m;
    for(int i=1; i<=m; i++)cin>>w[i]>>c[i];
    for(int i=1; i<=m; i++)
        for(int j=0; j<=t; j++) {
            d[i][j]=(i==1?0:d[i-1][j]);
            if(w[i]<=j)d[i][j]=max(d[i][j],c[i]+d[i-1][j-w[i]]);
        }
    cout<<d[m][t]<<endl;
    return 0;
}

就到这里。

猜你喜欢

转载自www.cnblogs.com/zach20040914/p/10369727.html