算法——背包问题

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
#include<iostream>
#include<algorithm>
using namespace std;
const int N=1010;
int w[N],m[N],dp[N][N];
int main()
{
	int n,v;
	cin>>n>>v;
	for(int i=1;i<=n;i++)
	cin>>m[i]>>w[i];
	for(int i=1;i<=n;i++)
	for(int j=v;j>=0;j--)
	{
		dp[i][j]=dp[i-1][j];
		if(m[i]<=j) dp[i][j]=max(dp[i][j],dp[i-1][j-m[i]]+w[i]);
	}
	cout<<dp[n][v]<<endl;
	
 } 

当物品有四种,背包总重量为8时,对于如下的物品
在这里插入图片描述
可以通过表将各种情况下的最大值列出来
在这里插入图片描述
背包问题的核心代码就是

dp[i][j]=dp[i-1][j];
dp[i][j]=max(dp[i][j],dp[i-1][j-m[i]]+w[i]);

通过遍历可以选取的数量和背包的剩余重量再搭配上我们的核心代码就可以得到上图中的数据。
至于为什么核心代码是那样的,我们通过上图中的数据来理解。
当我们i=3,j=6时,最大值要在dp[i][j]与dp[i-1][j-m[i]]+w[i]中选较大的值,此时dp[i][j]表示的是dp[2][5]的值,也就是7。dp[i-1][j-m[i]]+w[i]的值为dp[2][2]+5,结果为8。相比之下8更大,所以这个空填8。

dp[i-1][j-m[i]]+w[i]的作用是,找到可以选取数量比当前可以选取数量少一个,并且选取剩余体积刚好能装下当前序号的物品的情况,加上当前序号物品的价值。所以每次的情况对应的值都是当前情况的最优值。

优化
.01背包问题的时间复杂度很难优化,但可以对其空间进行优化。可以将dp的二维数组用一维数组代替,用剩余的重量来表示状况,当每个物品的被选取情况发生变化时,数组内存的会是较大的值,不断地更新成最大的值。

#include<iostream>
#include<algorithm>
using namespace std;
const int N=1010;
int w[N],m[N],dp[N];
int main()
{
	int n,v;
	cin>>n>>v;
	for(int i=1;i<=n;i++) cin>>m[i]>>w[i];
	for(int i=1;i<=n;i++)
	for(int j=v;j>=m[i];j--)
	{
		if(m[i]<=j) dp[j]=max(dp[j],dp[j-m[i]]+w[i]);
	}
	cout<<dp[v]<<endl;
	
 } 

完全背包问题

有 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
#include<iostream>
#include<algorithm>
using namespace std;
const int N=1010;
int dp[N],n,v,m[N],w[N];
int main()
{
	cin>>n>>v;
	for(int i=1;i<=n;i++) cin>>m[i]>>w[i];
	for(int i=1;i<=n;i++)
	for(int j=m[i];j<=v;j++)
	dp[j]=max(dp[j],dp[j-m[i]]+w[i]);
	cout<<dp[v]<<endl;
}

和01背包的代码很相似,只要将剩余体积从大到小循环改成从小到大循环就行。但其中的思路与01背包的思路还是有差别的。
从小到大是因为,之后的选择是基于当前选择而更新的。先将剩余体积从m[i]到v枚举一遍,当前体积刚好能装一个序号为i的物品时,则将其填入数组,然后剩余体积刚好又能装一个时,再将其填入数组。这样就达到了选多个物品的要求。在这基础上分别将不同序号的物品遍历比较,取剩余体积一定时,价值最大的情况填入数组。最后剩余体积为v的情况就为最大值。

多重背包问题

有 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
#include<iostream>
#include<algorithm>
using namespace std;
const int N=110;
int dp[N],n,v,m[N],w[N],k[N];
int main()
{
	cin>>n>>v;
	for(int i=0;i<n;i++) cin>>m[i]>>w[i]>>k[i];
	for(int i=0;i<n;i++)
	for(int j=v;j>=0;j--)
	for(int c=1;c<=k[i]&&c*m[i]<=j;c++)
	dp[j]=max(dp[j],dp[j-c*m[i]]+c*w[i]);
	cout<<dp[v]<<endl;
}

当数据量小的时候,可以将不同数量也作为一次循环来当做01背包问题做。
多加的循环是不同的物品取不同数量的价值情况。

当数据量大时,就要使用二进制优化了。
例如一个物品数量为7,可以用1 ,2 ,4三个数来表示1-7之间的取值情况。

用vector容器可以减少内存的使用

#include<iostream>
#include<vector>
#include<algorithm>
using namespace std;
const int N=2010;
int n,m;
int f[N];
struct Good
{
	int v,w;
};
int main()
{
	vector<Good> goods;
	cin>>n>>m;
	for(int i=0;i<n;i++)
	{
	    int v,w,s;
	    cin>>v>>w>>s;
	    for(int k=1;k<=s;k*=2)
	    {
	        s-=k;
	        goods.push_back({v*k,w*k});
	    }
	    if(s>0) goods.push_back({v*s,w*s});
	}
	for(auto good: goods)
	for(int j=m;j>=good.v;j--)
	f[j]=max(f[j],f[j-good.v]+good.w);
	cout<<f[m]<<endl;
}

如果不用容器的话,可以替换成普通数组一样可以达成效果

#include<iostream>
#include<vector>
#include<algorithm>
#include<cstring>
using namespace std;
const int N=2010;
int n,m;
int f[N],a[N],b[N];
int x=0,y=0;
int main()
{cin>>n>>m;
	for(int i=0;i<n;i++)
	{    int v,w,s;
	    cin>>v>>w>>s;
	    for(int k=1;k<=s;k*=2)
	    {s-=k;
	        a[x]=k*v;
	        b[x]=k*w;
	        x++;}
	    if(s>0) 
	    {a[x]=s*v;
	        b[x]=s*w;
	        x++;}}
	for(int q=0;q<=x;q++)
	for(int j=m;j>=a[q];j--)
	f[j]=max(f[j],f[j-a[q]]+b[q]);
	cout<<f[m]<<endl;
}

将数量用二进制优化法来表示,这样将多个数量的一个物品变成了一个数量的多个体积,价值一样的物品,在使用01背包的方法,就能找到最大值。

  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Go语言(也称为Golang)是由Google开发的一种静态强类型、编译型的编程语言。它旨在成为一门简单、高效、安全和并发的编程语言,特别适用于构建高性能的服务器和分布式系统。以下是Go语言的一些主要特点和优势: 简洁性:Go语言的语法简单直观,易于学习和使用。它避免了复杂的语法特性,如继承、重载等,转而采用组合和接口来实现代码的复用和扩展。 高性能:Go语言具有出色的性能,可以媲美C和C++。它使用静态类型系统和编译型语言的优势,能够生成高效的机器码。 并发性:Go语言内置了对并发的支持,通过轻量级的goroutine和channel机制,可以轻松实现并发编程。这使得Go语言在构建高性能的服务器和分布式系统时具有天然的优势。 安全性:Go语言具有强大的类型系统和内存管理机制,能够减少运行时错误和内存泄漏等问题。它还支持编译时检查,可以在编译阶段就发现潜在的问题。 标准库:Go语言的标准库非常丰富,包含了大量的实用功能和工具,如网络编程、文件操作、加密解密等。这使得开发者可以更加专注于业务逻辑的实现,而无需花费太多时间在底层功能的实现上。 跨平台:Go语言支持多种操作系统和平台,包括Windows、Linux、macOS等。它使用统一的构建系统(如Go Modules),可以轻松地跨平台编译和运行代码。 开源和社区支持:Go语言是开源的,具有庞大的社区支持和丰富的资源。开发者可以通过社区获取帮助、分享经验和学习资料。 总之,Go语言是一种简单、高效、安全、并发的编程语言,特别适用于构建高性能的服务器和分布式系统。如果你正在寻找一种易于学习和使用的编程语言,并且需要处理大量的并发请求和数据,那么Go语言可能是一个不错的选择。
Go语言(也称为Golang)是由Google开发的一种静态强类型、编译型的编程语言。它旨在成为一门简单、高效、安全和并发的编程语言,特别适用于构建高性能的服务器和分布式系统。以下是Go语言的一些主要特点和优势: 简洁性:Go语言的语法简单直观,易于学习和使用。它避免了复杂的语法特性,如继承、重载等,转而采用组合和接口来实现代码的复用和扩展。 高性能:Go语言具有出色的性能,可以媲美C和C++。它使用静态类型系统和编译型语言的优势,能够生成高效的机器码。 并发性:Go语言内置了对并发的支持,通过轻量级的goroutine和channel机制,可以轻松实现并发编程。这使得Go语言在构建高性能的服务器和分布式系统时具有天然的优势。 安全性:Go语言具有强大的类型系统和内存管理机制,能够减少运行时错误和内存泄漏等问题。它还支持编译时检查,可以在编译阶段就发现潜在的问题。 标准库:Go语言的标准库非常丰富,包含了大量的实用功能和工具,如网络编程、文件操作、加密解密等。这使得开发者可以更加专注于业务逻辑的实现,而无需花费太多时间在底层功能的实现上。 跨平台:Go语言支持多种操作系统和平台,包括Windows、Linux、macOS等。它使用统一的构建系统(如Go Modules),可以轻松地跨平台编译和运行代码。 开源和社区支持:Go语言是开源的,具有庞大的社区支持和丰富的资源。开发者可以通过社区获取帮助、分享经验和学习资料。 总之,Go语言是一种简单、高效、安全、并发的编程语言,特别适用于构建高性能的服务器和分布式系统。如果你正在寻找一种易于学习和使用的编程语言,并且需要处理大量的并发请求和数据,那么Go语言可能是一个不错的选择。
对于背包问题的贪心算法,可以按照物品的单位重量价值进行排序,然后依次选择单位重量价值最高的物品放入背包中,直到背包装满或者没有可选的物品为止。这个算法可以通过以下Java代码实现: ```java public class KnapsackGreedy { public static int maxValue(int[] values, int[] weights, int max){ if(values == null || values.length == 0){ return 0; } if(weights == null || weights.length == 0){ return 0; } if(max <= 0){ return 0; } int n = values.length; double[] valuePerWeight = new double[n]; for(int i=0; i<n; i++){ valuePerWeight[i] = (double) values[i] / weights[i]; } int[] sortedIndex = new int[n]; for(int i=0; i<n; i++){ sortedIndex[i] = i; } Arrays.sort(sortedIndex, (a, b) -> Double.compare(valuePerWeight[b], valuePerWeight[a])); int maxValue = 0; int currentWeight = 0; for(int i=0; i<n; i++){ int index = sortedIndex[i]; if(currentWeight + weights[index] <= max){ maxValue += values[index]; currentWeight += weights[index]; } } return maxValue; } public static void main(String[] args) { int[] values={6,3,5,4,6}; int[] weights={2,2,6,5,4}; int max = 10; System.out.println(maxValue(values,weights,max)); } } ``` 以上是一个简单的贪心算法实现,它通过计算每个物品的单位重量价值,并按照降序对物品进行排序。然后依次选择单位重量价值最高的物品放入背包中,直到背包装满或者没有可选的物品为止。该算法的时间复杂度为O(nlogn),其中n为物品的数量。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* [背包问题(Java实现)——贪心算法](https://blog.csdn.net/qq_40956679/article/details/83684383)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_1"}}] [.reference_item style="max-width: 50%"] - *2* *3* [java语言贪心算法背包问题](https://blog.csdn.net/ityw520/article/details/121514232)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_1"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值