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,所以对最终价值无影响,这样初始化后的状态表示就可以把“恰”字去掉。

在背包问题中,有两种解决办法,一种是二维数组,一种是一维数组。

例题:

洛谷P1048

乾坤大挪移

一般情况,,01背包问题的解决方法:

//二维数组:
for(int i=1;i<=n;i++)
    for(int j=v;j>=0;j--)//v指的是背包容量
        f[i][j]=max(f[i-1][j],f[i-1][j-w[i]]+c[i]//w[i]是第i件物品的价值
cout<<f[n][v];

相较于二维数组来说,一维数组会相对较快一些,所以掌控一维数组的01背包问题,是十分重要的。

//一维数组
for(i=1;i<=n;i++)
    for(j=v;j>=0;j--)
        f[j]=max(f[j-h[i]]+w[i], f[j]);
cout<<f[v]<<endl;

此题题解:

#include<bits/stdc++.h>
using namespace std;
int t,m,i,j;
int h[105],w[105],f[50000];
int max(int x,int y)//自定义的比较大小函数
{//其实在algorithm函数库中有自带max和min比较函数
    return x>y? x:y;
}
int main()
{
    cin>>t>>m;
    for(i=1;i<=m;i++)
    cin>>h[i]>>w[i];
    for(i=1;i<=m;i++)
    for(j=t;j>=h[i];j--)
    {
        f[j]=max(f[j-h[i]]+w[i], f[j]);//动态规划方程
    }
    cout<<f[t]<<endl;
    return 0;
}

嗯呐嗯呐,01背包就是这个样子!!!