背包问题

Posted vasairg

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了背包问题相关的知识,希望对你有一定的参考价值。

背包问题

来源

完全基于中山纪念中学 宋新波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{ egin{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} ight. ]

  • 答案为(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{ egin{array}{rcl} 0 & &{i=0(边界条件)}max{f[i-1,j-x*v[i]]+x*w[i]}& &{0<=x<=j / v[i]}\end{array} ight. ]

  • 答案为(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{ egin{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} ight. ]

  • 答案为(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:多重背包(未完待续)

以上是关于背包问题的主要内容,如果未能解决你的问题,请参考以下文章

使用喷气背包导航将自定义过渡动画添加到底部导航设置

在片段的后按防止使用导航图调用前一个片段的 onViewCreated

Android Jetpack 导航禁用滚动位置

0-1背包问题的回溯法代码

c语言背包问题,求高手解答

动态规划_01背包_完全背包_多重背包_分组背包