动态规划之完全背包、多重背包

前言

上一篇博客刚讲了01背包,本章所要讲的完全背包和多重背包和01背包属于同一问题,它们三个的解决思想和数学模型相同,唯一不同的是约束。因此没看过01背包的建议一定先看一下01背包,另外在这里同样给大家推荐两篇博客:完全背包、多重背包。好,下面进入正题。

完全背包

场景

我们仍使用01背包的场景,马上我们就会发现这两个其实是同一问题:
同样是这档节目,给嘉宾发一个购物车,然后准备一些商品,但每个商品不再只有一个,而是无限个,在1分钟的时间内嘉宾可以随意往购物车中装任意商品任意个数,只要购物车装的下,然后购物车里面的商品就属于嘉宾了,同样我们要求购物车中的商品的价值最大,这就是完全背包问题,为了便于讲解,我们建立一下数学描述模型。

数学模型

我们使用变量V描述购物车的容量;
使用P描述所选商品的总价值;
然后使用两个含有n个元素的集合:
vi ∈ \in {v1,v2,v3,…,vn},(0<=i<=n),vi表示第i种商品的体积;
pi ∈ \in {p1,p2,p3,…,pn},(0<=i<=n),pi表示第i种商品的价值。
最后我们再用一个变量xi表示第i种商品的个数,注意此时xi>=0。我们的目的是求所有商品的最大值,即:
P = m a x ( p 1 x 1 + p 2 x 2 + . . . + p i x i ) P=max(p_1x_1+p_2x_2+...+p_ix_i) P=max(p1x1+p2x2+...+pixi)
这个结果需要符合一个约束:
V > = ( v 1 x 1 + v 2 x 2 + . . . + v i x i ) V>=(v_1x_1+v_2x_2+...+v_ix_i) V>=(v1x1+v2x2+...+vixi)
同样我们定义函数P=func(i,j)表示体积j下前i种商品组合的最优解,当i=n,j=V时结果即所求,子问题的构建相同,我们先只考虑第i个商品,因为此时xi>=0所以:
P = m a x { f u n c ( i − 1 , j − x i v i ) + p i } ( 0 < = x i v i < = j ) P=max \{func(i-1,j-x_iv_i)+p_i\} (0<=x_iv_i<=j) P=max{func(i1,jxivi)+pi}(0<=xivi<=j)
到这里相信很多人已经发现了,01背包其实就是完全背包的特例,我们只需把 x i x_i xi的值再加一个限制, 0 < = x i < = 1 0<=x_i<=1 0<=xi<=1,就变成了01背包问题。下面我们看代码:

代码实现

class solution {
	vector<int> _p;	//商品价值集合
	vector<int> _v;	//商品体积集合
	int n;	//商品数量
	int max_v;	//购物车容量
public:
	solution(const vector<int>& p, const vector<int>& v, int m) {
		_p = p;
		_v = v;
		n = _p.size() - 1;
		max_v = m;
	}

	int func() {
		vector<vector<int>> dp(n + 1, vector<int>(max_v + 1, 0));

		for (int i = 0; i <= n; i++)
			dp[i][0];
		for (int j = 0; j <= max_v; j++)
			dp[0][j];
		for (int i = 1; i <= n; i++) {
			for (int j = 1; j <= max_v; j++) {
				for (int k = 0; k * _v[i] <= j; k++)
					dp[i][j] = max(dp[i][j], dp[i - 1][j - k * _v[i]] + k * _p[i]);
			}
		}
		return dp[n][max_v];
	}
};

多重背包

场景

多重背包也和01背包一样,是完全背包的一个特例,我们先来看场合:
同样是这档节目,给嘉宾发一个购物车,然后准备一些商品,但每个商品不再只有一个,也不是无限个,而是有限个数,它有可能是任意非负数,在1分钟的时间内嘉宾可以随意往购物车中装任意商品不超过限制的个数,只要购物车装的下,然后购物车里面的商品就属于嘉宾了,同样我们要求购物车中的商品的价值最大,这就是多重背包问题,到这里我相信大家应该自己也能独立写出它的数学模型了吧。

数学模型

我们使用变量V描述购物车的容量;
使用P描述所选商品的总价值;
这里我们使用三个含有n个元素的集合,多的那个集合表示每个商品的个数:
vi ∈ \in {v1,v2,v3,…,vn},(0<=i<=n),vi表示第i种商品的体积;
pi ∈ \in {p1,p2,p3,…,pn},(0<=i<=n),pi表示第i种商品的价值;
ki ∈ \in {k1,k2,k3,…,kn},(0<=i<=n),ki表示第i种商品的个数。
最后我们再用一个变量xi表示第i种商品的个数,注意此时0<=xi<=ki。我们的目的是求所有商品的最大值,即:
P = m a x ( p 1 x 1 + p 2 x 2 + . . . + p i x i ) P=max(p_1x_1+p_2x_2+...+p_ix_i) P=max(p1x1+p2x2+...+pixi)
这个结果需要符合一个约束:
V > = ( v 1 x 1 + v 2 x 2 + . . . + v i x i ) V>=(v_1x_1+v_2x_2+...+v_ix_i) V>=(v1x1+v2x2+...+vixi)
同样我们定义函数P=func(i,j)表示体积j下前i种商品组合的最优解,当i=n,j=V时结果即所求,子问题的构建相同,我们先只考虑第i个商品,所以:
P = m a x { f u n c ( i − 1 , j − x i v i ) + p i } ( 0 < = x i v i < = j & x i < = k i ) P=max \{func(i-1,j-x_iv_i)+p_i\} (0<=x_iv_i<=j \& x_i<=k_i) P=max{func(i1,jxivi)+pi}(0<=xivi<=j&xi<=ki)
这个代码我建议大家自己写一下,非常简单,完全背包的变形。

代码实现

class solution {
	vector<int> _p;	//商品价值集合
	vector<int> _v;	//商品体积集合
	vector<int> _k;
	int n;	//商品数量
	int max_v;	//购物车容量
public:
	solution(const vector<int>& p, const vector<int>& v,const vector<int>& k, int m) {
		_p = p;
		_v = v;
		_k = k;
		n = _p.size() - 1;
		max_v = m;
	}

	int func() {
		vector<vector<int>> dp(n + 1, vector<int>(max_v + 1, 0));

		for (int i = 0; i <= n; i++)
			dp[i][0];
		for (int j = 0; j <= max_v; j++)
			dp[0][j];
		for (int i = 1; i <= n; i++) {
			for (int j = 1; j <= max_v; j++) {
				for (int k = 0; k <= _k[i] && k * _v[i] <= j; k++)
					dp[i][j] = max(dp[i][j], dp[i - 1][j - k * _v[i]] + k * _p[i]);
			}
		}
		return dp[n][max_v];
	}
};

这里要注意一下, k < = _ k i k<=\_k_i k<=_ki要写在 k ∗ _ v [ i ] < = j k*\_v[i]<=j k_v[i]<=j之前,否则会出现问题。
好,到这里三个背包问题就讲完了,其实我们只要掌握了完全背包其实就掌握了另外两种背包问题,最后感谢大家的捧场,若有错误之处还望大家不厌其烦的指出,我会继续进步给大家呈现更好的文章!

你可能感兴趣的:(动态规划)