01背包问题 详细分析

01背包问题

问题描述

背包容量为V,有n件物品,每件物品体积v[i],价值c[i],问如何装使背包总价值最大。

问题分析

对每一个物品,有且仅有两种状态:放入背包和不放入背包。动态规划问题符合无后效性的特点,也就是说决策仅依赖于当前状态,我们首先来考虑第i件物品(不管前i-1件是怎么选择的,我们只考虑第i件),它分为两种情况:当前空间不足以放入第i件物品,或者当前空间可以放入第i件物品。我们取其中价值最大的一种方法。我们用一个数组f[i][v]表示 i件物品放入容量为v的背包中时的最大价值。
公式如下:
空间不足以放入第i件时,最大价值就等于前i-1件物品放入背包的最大价值 f[i][v]=f[i-1][v]
空间足够时,就要考虑放入第i件和不放入那种情况总价值最大:f[i][v]=max(f[i-1][v],f[i-1][v-v[i]]+c[i])
v-v[i]要确保大于零,这样才能保证第i件物品有足够的空间放入。
代码如下:

for(int i=1;i<=n;i++)
{
	for(int vi=0;vi<=V;vi++)
	{
		if(vi<v[i]) f[i][vi]=f[i-1][vi]; //当空间不足时第i件物品放入空间为vi的最大价值等于前i-1件物品放入背包为vi的价值。
		else f[i][vi]=max(f[i-1][vi],f[i-1][vi-v[i]]+c[i]); //当空间足够时比较放入和不放入第i间物品的最大价值。
	}
}

数组一定要初始化,不然会出错的。
完整代码:

#include <iostream>
#include <cstring>
#define Author JokerNoCry
#define Date 2020/4/5
using namespace std;
int main()
{
    int V,n;
    int v[35],c[35];
    int f[35][210];
    memset(f,0,sizeof(f));
    cin>>V>>n;
    for(int i=1;i<=n;i++) cin>>v[i]>>c[i];
    for(int i=1;i<=n;i++)
    {
        for(int vi=0;vi<=V;vi++)
        {
            if(vi<v[i]) f[i][vi]=f[i-1][vi];
            else f[i][vi]=max(f[i-1][vi],f[i-1][vi-v[i]]+c[i]);
        }
    }
    cout<<f[n][V]<<endl;
    return 0;
}

空间优化

上面的过程在时间上已经很难优化了,但是他的空间复杂度O(Vn)还可以优化到O(V).
由上述分析可以发现第i件物品的结果仅与第i-1次有关,那么我们可以直接用一维数组f[v]来表示i件物品装入容量为v的背包时的最大价值。以上代码更新成:

  • 空间不足以放入第i件时,最大价值就等于前i-1件物品放入背包的最大价值 f[v]=f[v]
  • 空间足够时,就要考虑放入第i件和不放入那种情况总价值最大:f[v]=max(f[v],f[v-v[i]]+c[i])
    完整代码:
#include <iostream>
#include <cstring>
#define Author JokerNoCry
#define Date 2020/4/5
using std::max;
using std::cin;
using std::cout;
using std::endl;
int main()
{
    int m,n;
    int w[35],c[35],f[210];
    memset(f,0,sizeof(f));
    cin>>m>>n;
    for(int i=0;i<n;i++) cin>>w[i]>>c[i];
    for(int i=0;i<n;i++)
    {
        for(int fi=m;fi>=w[i];fi--)
        {
            f[vi]=max(f[vi],f[vi-w[i]]+c[i]);
        }
    }
    cout<<v[m]<<endl;
    return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_30445397/article/details/105321953
今日推荐