01背包问题——<DP>

来源:互联网 发布:wp8软件下载 编辑:程序博客网 时间:2024/06/10 20:52
01背包题目的雏形是:
有N件物品和一个容量为V的背包。第i件物品的体积是c[i],价值是w[i]。求解将哪些物品装入背包可使价值总和最大。
从这个题目中可以看出,01背包的特点就是:每种物品仅有一件,可以选择放或不放。
其状态转移方程是:
f[i][v]=max{f[i-1][v],f[i-1][v-c[i]]+w[i]}

对于这方方程其实并不难理解,方程之中,现在需要放置的是第i件物品,这件物品的体积是c[i],价值是w[i],因此f[i-1][v]代表的就是不将这件物品放入背包,而f[i-1][v-c[i]]+w[i]则是代表将第i件放入背包之后的总价值,比较两者的价值,得出最大的价值存入现在的背包之中。

题目描述:

假设山洞里共有a,b,c,d ,e这5件宝物(不是5种宝物),它们的重量分别是2,2,6,5,4,它们的价值分别是6,3,5,4,6,现在给你个承重为10的背包, 怎么装背包,可以才能带走最多的财富。

有编号分别为a,b,c,d,e的五件物品,它们的重量分别是2,2,6,5,4,它们的价值分别是6,3,5,4,6,现在给你个承重为10的背包,如何让背包里装入的物品具有最大的价值总和?

    此例题参考博客:动态规划之01背包问题(最易理解的讲解)

先对表进行大概的说明,前面三列是物品名字,重量和价值。后面1到10表示背包容量。

e3表示背包容量为3,当前物品为e。 装不下

d3表示背包容量为3,当前物品为e,d。装不下

c3表示背包容量为3,当前物品为e,d,c。 装不下

b3表示背包容量为3,当前物品为e,d,c,b 可以装b物品,所以值为b物品的价值3

a3表示背包容量为3,当前物品为e,d,c,b ,a 这时根据状态转移方程,比较b3和b1+a的价值的值。

后者更大,所以a3值为6.


当时看了上面博客的讲解后自己画出了上面这张表,可是比较好奇为什么要从最后一件物品开始往里面装,不能从第一件物品直接开始装嘛?

于是再次从第一件物品以同样的填法进行填表,发现其实结果是一样的,并没有影响。


这里对e8进行说明,d8为11,当前容量8减去e的重量4=4,所以寻找d4值 为9  9+6=15>11 所以e8的值更新为15

一道例题:有一个容量为m(1<=m<=4000000)的背包,有n(1<=n<=16)个物品,每个物品有体积v(1<=v<=2012)和价值w(0<=2012),现在要你选择一些物品,使得背包所装物品的总价值最大。

C++代码:

#include <iostream>#include <memory.h>using namespace std;struct wupin{    int v;//体积    int w;//价值}a[10000];int dp[10000][10000];int main(){    int n,m;    cin>>m>>n;    memset(dp,0,sizeof(dp));    memset(a,0,sizeof(a));    for(int i=1;i<=n;i++)        cin>>a[i].v>>a[i].w;    for(int i=1;i<=n;i++)        for(int j=1;j<=m;j++)        {            if(j>=a[i].v)                dp[i][j]=max(dp[i-1][j],dp[i-1][j-a[i].v]+a[i].w);            else                dp[i][j]=dp[i-1][j];        }//    for(int i=1;i<=n;i++)//       {// for(int j=1;j<=m;j++)//            cout<<dp[i][j]<<' ';//            cout<<endl;//       }    cout << dp[n][m] << endl;    return 0;}
一般写法:

大小为j的背包是否放第i个物品,取决于大小为(j-a[i].v)的背包的最优解+a[i].w 是否大于当前不放这个物品的最优解的价值

#include <iostream>#include <memory.h>using namespace std;struct wupin{    int v;//体积    int w;//价值}a[10000];int dp[100000];int main(){    int n,m;    cin>>m>>n;    memset(dp,0,sizeof(dp));    memset(a,0,sizeof(a));    for(int i=0;i<n;i++)        cin>>a[i].v>>a[i].w;    for(int i=0;i<n;i++)        for(int j=m;j>=a[i].v;j--)            dp[j]=max(dp[j],dp[j-a[i].v]+a[i].w);    cout << dp[m] << endl;    return 0;}

最简洁的写法:

#include <cstdio>#include <algorithm>using namespace std;int f[1005];int n,m;int main(){    int w,v;    scanf("%d%d",&m,&n);    for(int i=1;i<=n;i++)    {        scanf("%d%d",&v,&w);        for(int j=m;j>=v;j--)            f[j]=max(f[j],f[j-v]+w);    }    printf("%d\n",f[m]);    return 0;}