Bootstrap

dp(01背包,完全背包,多重背包)详解附代码

前言

dp一直是自己弱势,某些题的状态方程方程是真不好想.0.0.
而背包问题一直是dp的入门级别问题,重新整理整理吧…写写博客也算加强记忆吧

一、01背包

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
通过上面的表格,可以知道当这5个物品放入容量为10的背包中,最大的价值为15,即dp[5][10] = 15。

for (int i = 1; i <= N; ++i) {
    for (int j = 0; j <= V; ++j) {
        if(j >= w[i]) {
            dp[i][j] = max(dp[i - 1][j - w[i]] + v[i], dp[i - 1][j]);
        }
        else {
            dp[i][j] = dp[i-1][j];
        }
    }
}

时间上是两重循环,时间复杂度O(NV),空间复杂度O(NV)。

除此,还可以进一步优化空寂复杂度:

在这里插入图片描述

for (int i = 1; i <= n; ++i)
    for (int j = v; j >= w[i]; --j)
        dp[j] = max(dp[j - w[i]] + v[i], dp[j]);

这样的空间复杂度就为O(V)了。

二、完全背包

在这里插入图片描述
在这里插入图片描述

for (int i = 1; i <= n; ++ i)
    for (int j = c[i]; j <= v; ++ j)
        dp[j] = max(dp[j - c[i]] + w[i], dp[j]);

可以发现:与01背包相比,完全背包只是第二重循环的顺序发生了改变。我们保证用较小容量的最大价值去更新较大容量的最大价值,不重不漏。时间复杂度O(VN),空间复杂度O(V)。

三、多重背包

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
多重背包问题限定了一种物品的个数,解决多重背包问题,也可以把它转化为0-1背包问题。

看代码:

#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
int N,V;
int w[100],v[100],num[100];
int f[100][100];

int MultiKnapsack()
{
	int nCount = 0;
	memset(f,0,sizeof(f));
	for (int i = 1;i <= N;i++)
	{
		for (int j = w[i];j <= V;j++)
		{
			nCount = min(num[i],j/w[i]);
			for (int k = 0;k <= nCount;k++)
			{
				f[i][j] = max(f[i][j],f[i - 1][j - k * w[i]] + k * v[i]);
			}
		}
	}
	return f[N][V];
}
int main()
{

	cin>>N>>V;
	for(int i=1;i<=N;i++) cin>>w[i];
	for(int i=1;i<=N;i++) cin>>v[i];
	for(int i=1;i<=N;i++) cin>>num[i];
	cout<<MultiKnapsack()<<endl;

	return 1;
}
/*
input:
3 8
1 2 2
6 10 20
10 5 2
output:
64
*/


#include <iostream>
#include <cstring>
using namespace std;

 int N ;//物品个数
 int W;//背包容量
int Weight[110];
int Value[110] ;
int Num[110];

int f[110] ;///用f[j]表示,第i次循环后,f[j]中存储的前i件物品放入容量为j的背包可获得的最大价值

void ZeroOnePack(int nWeight,int nValue)
{
	for (int j = W;j >= nWeight;j--)
	{
		f[j] = max(f[j],f[j - nWeight] + nValue);
	}
}


void CompletePack(int nWeight,int nValue)
{
	for (int j = nWeight;j <= W;j++)
	{
		f[j] = max(f[j],f[j - nWeight] + nValue);
	}
}

int MultiKnapsack()
{
    memset(f,0,sizeof(f));
	int k = 1;
	int nCount = 0;
	for (int i = 1;i <= N;i++)
	{
		if (Weight[i] * Num[i] >= W)
		{
			CompletePack(Weight[i],Value[i]);
		}
		else
		{
			k = 1;
			nCount = Num[i];
			while(k <= nCount)
			{
				ZeroOnePack(k * Weight[i],k * Value[i]);
				nCount -= k;
				k *= 2;
			}
			ZeroOnePack(nCount * Weight[i],nCount * Value[i]);
		}
	}
	return f[W];
}

int main()
{
    cin>>N>>W;
	for(int i=1;i<=N;i++) cin>>Weight[i];
	for(int i=1;i<=N;i++) cin>>Value[i];
	for(int i=1;i<=N;i++) cin>>Num[i];
	cout<<MultiKnapsack()<<endl;

	return 1;
}


;