动态规划--背包问题

0-1 背包问题

N件物品 背包最大重量W,
每个物品都有value和w
每个物品都只能取一次,
重量不超过W的情况下
求价值最大。
0<N,W<1000
0<wi,valuei<1000
输入:
N W
N行:重量和价值
wi valuei
示例:
4 5
1 2
2 4
3 4
4 5
8
思路:
先用表格即二维数组的想法规划一下,将没种情况都列举出来,最后找到最大值即可。

f[i][j]  表示在j的重量下此时,只考虑前i个物品的最大价值
此时俩种情况:
1.不算i物品,此时f[i][j] = f[i-1][j];即上一行时(不包括第i个物品的最大价值)
2.计算i物品:f[i][j] = f[i-1][j-w[i]]+value[i];
即:将减去i物品的重量时的最大价值+ i物品的价值
将两种情况对比,取最大的值赋给f[i][j]
#include<iostream>
#include<string>
#include<algorithm>
#include<cmath>
using namespace std;
int const N = 1010;
int f[N][N]; // f[i][j] i代表物品,j代表重量,表示在j重量下i个物品所能达到的最大价值
int m,n;
int main()
{
	int w[N],value[N];
	cin>>n>>m;
	for(int i=1;i<=n;i++)
		cin>>w[i]>>value[i];
	for(int i = 1;i<=n;i++)
	{
		for(int j =0;j<=m;j++)
		{
			f[i][j] = f[i-1][j];
			if(j>=w[i]) // 如果j质量小于i的质量说明放不进去所以必须>=才考虑俩种情况 
			{
					f[i][j] = max(f[i][j],f[i-1][j-w[i]]+value[i]);	
			}
		}
	}
	int res =0;
	for(int i =1;i<=n;i++) res= max(res,f[i][m]);
	cout<<res<<endl;
}

此时算法的时间复杂度为O(n2),一般测试平台每秒运行107次或者108

优化算法:
将二维数组变为一维数组

#include<iostream>
#include<string>
#include<algorithm>
#include<cmath>
using namespace std;
int const N = 1010;
int f[N]; // f[i] 表示在i重量下个物品所能达到的最大价值
int m,n;
int main()
{
	int w[N],value[N];
	cin>>n>>m;
	for(int i=1;i<=n;i++)
		cin>>w[i]>>value[i];
	for(int i = 1;i<=n;i++) // 外层循环代表i个物体,时候在j重量下的最大价值
	{
		for(int j =m;j>=w[i];j--) // 这个时候没有i-1层所以要从大到小排序
		{
			f[j]=max(f[j],f[j-w[i]]+value[i]);
		}
	}
	int res =f[m];
	cout<<res<<endl;
}

完全背包问题

跟0-1背包不同,此时物体i可以取无限次

/*
f[i] 表示总重量为i的情况下,最大价值多少
在0-1背包问题下,从大到小排表示在没有取i的情况下,此时的最大价值就是上一个物品的最大价值,即i取0次
for(int i =1;i<=n;i++)
for(int j =m;j>=v[i];j--)
f[j]= max(f[j],f[j-v[i]]);
因此完全背包问题只需要将排序改变就变成了取无数次后的结果,因为这就是取反的效果
result = max(f[0.....m])
for(int i =1;i<=n;i++)
for(int j =v[i]; j<=m;j++)
	f[j]= max(f[j],f[j-w[i]]+value[i]);
*/

此时代码为:

#include<iostream>
#include<string>
#include<algorithm>
using namespace std;
const int N= 1010;
int f[N];
int m,n;
int w[N],value[N];
int main()
{
	cin>>n>>m;
	for(int i =1;i<=n;i++)
		cin>>w[i]>>value[i];
	for(int i =1 ;i<=n;i++)
	{
		for(int j =w[i];j<=m;j++)
			f[j] = max(f[j],f[j-w[i]]+value[i]); 
	}
	cout<<f[m]<<endl;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值