IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 数据结构与算法 -> 背包问题(四种) -> 正文阅读

[数据结构与算法]背包问题(四种)

背包问题

一、背包模型(定义)

01背包: 有N个物品和一个容量为V的背包,每一个物品有两个属性,一个是它的体积Vi,另一个是它的价值Wi(这里的价值其实是权重的意思),每件物品最多只能用一次(即0次或者1次);问题为从这些物品中挑一些物品,使得总体积 ≤ V,目标是使我们选出的这些物品的总价值最大,最大值是多少?

完全背包:每件物品能用无限次

多重背包:每件物品最多有Si个

分组背包: 物品有N组,每组物品里有若干个,每组里最多选一个物品

注:不一定要装满背包

二、01背包

题目

N 件物品和一个容量是 V 的背包。每件物品只能使用一次。

i 件物品的体积是 vi ,价值是 wi

求解将哪些物品装入背包,可使这些物品的总体积不超过背包容量,且总价值最大。
输出最大价值。

输入格式

第一行两个整数,N,V,用空格隔开,分别表示物品数量和背包容积。

接下来有 N 行,每行两个整数 vi,wi,用空格隔开,分别表示第 i 件物品的体积和价值。

输出格式

输出一个整数,表示最大价值。

数据范围

0 < N,V ≤ 1000
0 < vi,wi ≤ 1000

输入样例

4 5
1 2
2 4
3 4
4 5

输出样例:

8

题意

在这里插入图片描述

思路

在这里插入图片描述

图解:

状态表示f(i,j):考虑需要几维来表示状态,每个状态的含义是什么

集合:考虑f(i,j)表示哪一个集合,01背包问题中,表示所有满足下列两个条件的选法的集合

属性:01背包问题中,集合中所有选法的价值的最大值

状态计算:如何把每一个f(i,j)状态算出来

f(i,j)的集合划分中的含i的集合的计算:由于所有的选法都包含第i个物品,所以先把第i个物品去掉,然后求最大值,然后再把第i个物品加上(可能为空集:当j<vi时)

注:Dp优化一般来说都是对Dp问题的代码或者计算方程做一个等价变形

二维AC代码

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>

using namespace std;

const int N=1010;

int n,m;//n表示所有物品的个数,m表示容量
int v[N],w[N];//v表示体积,w表示价值
int f[N][N];//表示状态

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

一维AC代码

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>

using namespace std;

const int N=1010;

int n,m;//n表示所有物品的个数,m表示容量
int v[N],w[N];//v表示体积,w表示价值
int f[N];//表示状态

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

三、完全背包

题目

N 种物品和一个容量是 V 的背包,每种物品都有无限件可用。

i 种物品的体积是 vi,价值是 wi

求解将哪些物品装入背包,可使这些物品的总体积不超过背包容量,且总价值最大。
输出最大价值。

输入格式

第一行两个整数,N,V,用空格隔开,分别表示物品种数和背包容积。

接下来有 N 行,每行两个整数 vi,wi,用空格隔开,分别表示第 i 种物品的体积和价值。

输出格式

输出一个整数,表示最大价值。

数据范围

0 < N,V ≤ 1000
0 < vi,wi ≤ 1000

输入样例

4 5
1 2
2 4
3 4
4 5

输出样例:

10

思路1

在这里插入图片描述

朴素TLE代码

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>

using namespace std;

const int N=1010;

int n,m;//n表示所有物品的个数,m表示容量
int v[N],w[N];//v表示体积,w表示价值
int f[N][N];//表示状态

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

思路2

在这里插入图片描述

二维AC代码

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>

using namespace std;

const int N=1010;

int n,m;//n表示所有物品的个数,m表示容量
int v[N],w[N];//v表示体积,w表示价值
int f[N][N];//表示状态

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

一维AC代码

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>

using namespace std;

const int N=1010;

int n,m;//n表示所有物品的个数,m表示容量
int v[N],w[N];//v表示体积,w表示价值
int f[N];//表示状态

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

四、多重背包

多重背包问题I

题目

N 种物品和一个容量是 V 的背包。

i 种物品最多有 si件,每件体积是 vi,价值是 wi

求解将哪些物品装入背包,可使物品体积总和不超过背包容量,且价值总和最大。
输出最大价值。

输入格式

第一行两个整数,N,V,用空格隔开,分别表示物品种数和背包容积。

接下来有 N 行,每行三个整数 vi,wi,si,用空格隔开,分别表示第 i 种物品的体积、价值和数量。

输出格式

输出一个整数,表示最大价值。

数据范围

0 < N,V ≤ 100
0 < vi,wi,si ≤ 100

输入样例

4 5
1 2 3
2 4 1
3 4 3
4 5 2

输出样例:

10

思路

在这里插入图片描述

暴力AC代码

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>

using namespace std;

const int N=110;

int n,m;//n表示所有物品的个数,m表示容量
int v[N],w[N],s[N];//v表示体积,w表示价值
int f[N][N];//表示状态

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

多重背包问题II

题目

N 种物品和一个容量是 V 的背包。

i 种物品最多有 si件,每件体积是 vi,价值是 wi

求解将哪些物品装入背包,可使物品体积总和不超过背包容量,且价值总和最大。
输出最大价值。

输入格式

第一行两个整数,N,V,用空格隔开,分别表示物品种数和背包容积。

接下来有 N 行,每行三个整数 vi,wi,si,用空格隔开,分别表示第 i 种物品的体积、价值和数量。

输出格式

输出一个整数,表示最大价值。

数据范围

0 < N ≤ 1000
0 < V ≤ 2000
0 < vi,wi,si ≤ 2000

提示:

本题考查多重背包的二进制优化方法。

输入样例

4 5
1 2 3
2 4 1
3 4 3
4 5 2

输出样例:

10

AC代码

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>

using namespace std;

const int N=25000,M=2010;

int n,m;//n表示所有物品的个数,m表示容量
int v[N],w[N];//v表示体积,w表示价值
int f[N];//表示状态

int main()
{
	cin>>n>>m;
	int cnt=0;
	
	for(int i=1;i<=n;i++)
	{
		int a,b,s;
		cin>>a>>b>>s;
		int k=1;
		while(k<=s)
		{
			cnt++;
			v[cnt]=a*k;
			w[cnt]=b*k;
			s-=k;
			k*=2;
		}
		if(s>0)
		{
			cnt++;
			v[cnt]=a*s;
			w[cnt]=b*s;
		}
	}
	
	n=cnt;
	
	for(int i=1;i<=n;i++)
	{
		for(int j=m;j>=v[i];j--)
		{
			f[j]=max(f[j],f[j-v[i]]+w[i]);
		}
	}
	cout<<f[m]<<endl;
	
	return 0;
	
}

五、分组背包

题目

N 组物品和一个容量是 V 的背包。

每组物品有若干个,同一组内的物品最多只能选一个。
每件物品的体积是 vij,价值是 wij,其中 i 是组号,j 是组内编号。

求解将哪些物品装入背包,可使物品总体积不超过背包容量,且总价值最大。

输出最大价值。

输入格式

第一行有两个整数 N,V,用空格隔开,分别表示物品组数和背包容量。

接下来有 N 组数据:

  • 每组数据第一行有一个整数 Si,表示第 i 个物品组的物品数量;
  • 每组数据接下来有 Si 行,每行有两个整数 vij,wij,用空格隔开,分别表示第 i 个物品组的第 j 个物品的体积和价值;

输出格式

输出一个整数,表示最大价值。

数据范围

0 <N,V ≤ 100
0 < Si ≤ 100
0 < vij,wij ≤ 100

输入样例

3 5
2
1 2
2 4
1
3 4
1
4 5

输出样例:

8

思路

在这里插入图片描述

AC代码

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>

using namespace std;

const int N=110;

int n,m;//n表示所有物品的个数,m表示容量
int v[N][N],w[N][N],s[N];//v表示体积,w表示价值
int f[N];//表示状态

int main()
{
	cin>>n>>m;
	
	for(int i=1;i<=n;i++)
	{
		cin>>s[i];
		for(int j=0;j<s[i];j++)
		{
			cin>>v[i][j]>>w[i][j];
		}
	}	
	
	for(int i=1;i<=n;i++)
	{
		for(int j=m;j>=0;j--)
		{
			for(int k=0;k<s[i];k++)
			{
				if(v[i][k]<=j)
				{
					f[j]=max(f[j],f[j-v[i][k]]+w[i][k]);
				}
			}
		}
	}
	
	cout<<f[m]<<endl;
	
	return 0;
	
}
  数据结构与算法 最新文章
【力扣106】 从中序与后续遍历序列构造二叉
leetcode 322 零钱兑换
哈希的应用:海量数据处理
动态规划|最短Hamilton路径
华为机试_HJ41 称砝码【中等】【menset】【
【C与数据结构】——寒假提高每日练习Day1
基础算法——堆排序
2023王道数据结构线性表--单链表课后习题部
LeetCode 之 反转链表的一部分
【题解】lintcode必刷50题<有效的括号序列
上一篇文章      下一篇文章      查看所有文章
加:2022-03-03 16:39:43  更:2022-03-03 16:42:05 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/26 15:32:24-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码