背包问题

背包问题

来源

完全基于中山纪念中学 宋新波ppt的一次复习

动态规划的关键点

  • 最优化原理

子问题最优化结构

  • 无后效性

未来与过去无关

  • 状态

描述最优解的结构

  • 状态转移方程

递归定义最优解的值

  • 程序实现

用记忆化搜索或迭代法求解

No.1:01背包

问题

有N种物品和一个容量为V的背包。
第i种物品只有1个,体积是v[i],价值是w[i]。
选择物品装入背包使这些物品的体积总和不超过背包容量,且价值总和最大,求出这个最大价值。

分析

  • 状态

    \(f[i,j]\)表示用体积为j的背包装前i个物品能获得的最大价值。考虑第i种物品装或不装进行状态转移:

    \(f[i-1,j-v[i]]+w[i]\)(必须满足\(j>=v[i]\))

    • 不装

    \(f[i-1,j]\)

    • 两种情况取较大值。
  • 状态转移方程为:

\[f[i,j]=\left\{ \begin{array}{rcl} 0 & &{i=0(边界条件)}\\ f[i-1,j] & &{j<v[i]}\\ max(f[i-1,j],f[i-1,j-v[i]]+w[i])& &{j>=v[i]}\\ \end{array} \right. \]

  • 答案为\(f[n,v]\),时间复杂度为\(O(N*V)\)

code

#include <bits/stdc++.h> 
using namespace std;

const int Max=1e4+10;
int w[Max],v[Max];
int f[Max][Max]={0};

int main()
{
	int n,m;
	cin>>n>>m;
	for(int i=1; i<=n; i++)	cin>>v[i];
	for(int i=1; i<=n; i++)	cin>>w[i];
	for(int i=1; i<=n; i++)
		for(int j=0; j<=m; j++)
			if(j<v[i])	f[i][j]=f[i-1][j];
			else	f[i][j]=max(f[i-1][j],f[i-1][j-v[i]]+w[i]);
	cout<<f[n][m]<<endl;
	return 0;
}

No.2:完全背包

问题

有N种物品和一个容量为V的背包。
第i种物品有无穷个,体积是v[i],价值是w[i]。
选择物品装入背包使这些物品的体积总和不超过背包容量,且价值总和最大,求出这个最大价值。

分析

方法一

  • 状态:

\(f[i,j]\)表示用体积为j的背包装前i个物品能获得的最大价值。
考虑第\(i\)个物品装几个来进行状态转移,假设装\(x\)个,\(x\)的范围为\(0<=x<=j / v[i]\)

  • 状态转移方程:

\[f[i,j]=\left\{ \begin{array}{rcl} 0 & &{i=0(边界条件)}\\ max{f[i-1,j-x*v[i]]+x*w[i]}& &{0<=x<=j / v[i]}\\ \end{array} \right. \]

  • 答案为\(f[n,v]\),时间复杂度为\(O(V^2*\displaystyle \sum^N_{i=1}{\frac1{v[i]}})\)

code

#include <bits/stdc++.h> 
using namespace std;

const int Max=1e4+10;
int w[Max],v[Max];
int f[Max][Max]={0};

int main()
{
	int n,m;
	cin>>n>>m;
	for(int i=1; i<=n; i++)	cin>>v[i];
	for(int i=1; i<=n; i++)	cin>>w[i];
	for(int i=1; i<=n; i++)
		for(int j=0; j<=m; j++)
			for(int x=0; x<=j/v[i]; x++)
				f[i][j]=max(f[i][j],f[i-1][j-x*v[i]]+x*w[i]);
	cout<<f[n][m]<<endl;
	return 0;
}

方法二

  • 状态

\(f[i,j]\)表示用体积为j的背包装前\(i\)个物品能获得的最大价值。

  • 考虑第\(i\)个物品装或不装来进行状态转移:
    • 装:

    必须满足\(j>=v[i]\),由于物品有无穷多个,装一次后后面还可以再装,所以状态为\(f[i,j-v[i]]+w[i]\);

    • 不装:

    \(f[i-1,j]\)

  • 状态转移方程:

\[f[i,j]=\left\{ \begin{array}{rcl} 0 & &{i=0(边界条件)}\\ f[i-1,j] & &{j<v[i]}\\ max(f[i-1,j],f[i,j-v[i]]+w[i]) & &{j>=v[i]}\\ \end{array} \right. \]

  • 答案为\(f[n,v]\),时间复杂度为\(O(N*V)\)

code

#include <bits/stdc++.h> 
using namespace std;

const int Max=1e4+10;
int w[Max],v[Max];
int f[Max][Max]={0};

int main()
{
	int n,m;
	cin>>n>>m;
	for(int i=1; i<=n; i++)	cin>>v[i];
	for(int i=1; i<=n; i++)	cin>>w[i];
	for(int i=1; i<=n; i++)
		for(int j=0; j<=m; j++)
			if(j<v[i])	f[i][j]=f[i-1][j];
			else	f[i][j]=max(f[i-1][j],f[i][j-v[i]]+w[i]);
	cout<<f[n][m]<<endl;
	return 0;
}

No.3:多重背包(未完待续)

posted @ 2020-05-02 17:29  白菜道士  阅读(107)  评论(0编辑  收藏  举报