关于动态规划(Dynamic Programming)的若干思考 ------ [1.背包dp]

1.01 背包
动态转移方程:
f[i,j]表示前i个物品中选出总体积为j的物品所获得的最大价值。
f[i,j]=f[i-1,j](不选第i个物品)
f[i,j]=f[i-1,j-vi]+wi(选第i个物品)
(1)二维数组

open
#include<bits/stdc++.h>//simple
using namespace std;
const int maxm=2024;
int n,m;
int w[maxm],v[maxm],f[maxm][maxm];
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];
	return 0;
} 

(2) 滚动数组优化
open
#include<bits/stdc++.h>//optimize gundong
using namespace std;
const int maxm=2024;
int n,m;
int w[maxm],v[maxm],f[maxm][maxm];
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&1][j]=f[(i-1)&1][j];
			if(j>=v[i])
			f[i&1][j]=max(f[i&1][j],f[(i-1)&1][j-v[i]]+w[i]);		
		}
	cout <<f[n&1][m];
	return 0;
} 
(3) 因为每个阶段开始我们都进行了将f[i,j]=f[i-1,j]的操作本质是一种拷贝,所以我们直接省略第一维。
领域展开
#include<bits/stdc++.h>
using namespace std;
const int maxn=3600;
int n,m;
int v[maxn],w[maxn],f[maxn];
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--)//此处使用倒序(j不断缩小即表示状态是由第i-1转移到i的)
			f[j]=max(f[j],f[j-v[i]]+w[i]);
	cout << f[m];
	return 0; 	          
}

2.完全背包
01背包的正序循环对应着每个物品可以使用无数次

领域展开
#include<bits/stdc++.h>
using namespace std;
const int maxn=1005;
int n,m,v[maxn],w[maxn],f[maxn];
int main()
{
	cin >> m >> n;
	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];
	return 0;
}

3.多重背包
较01背包多了一组循环模拟一类物品所选个数(0到a[i])注意j-K*v[i]要大于零

领域展开
#include<bits/stdc++.h>
using namespace std;
const int maxn=36000;
int n,m;
int v[maxn],w[maxn],f[maxn],a[maxn];
int main()
{
	cin >> n >> m;
	for(int i=1;i<=n;i++)	cin >> v[i] >> w[i] >>a[i];
	for(int i=1;i<=n;i++)
		for(int j=m;j>=0;j--)
			for(int k=0;k<=a[i];k++)
			{
				if(k*v[i]>j) break;
				f[j]=max(f[j],f[j-k*v[i]]+k*w[i]);
			}
	cout << f[m];
	return 0; 	          
}

4.混合背包
顾名思义,就是大杂烩。但是正常结合会超时(多重背包三层循环),所以对多重背包进行二进制优化。
原理:
任意正数都能拆成2的非负整数次方相加。
所以我们将数量为Ci的第i种物品拆成P+2个。
这等价于原问题。

领域展开
#include <bits/stdc++.h>
using namespace std;
const int maxn = 22222024;
int n,m;	 
int v[maxn], w[maxn] , s[maxn],f[maxn] , cnt = 0;	 
int main()
{	
	cin >> m >> n;
	for(int i=1; i<=n; i++)
	{
		int x,y,z;
		cin >> x >> y >> z;
		if(z==0) 
		{
			v[++cnt]=-x;
			w[cnt]=y;
			continue;
		}
		for(int j=1;j<=z;j<<=1)
		{
			v[++cnt] = j*x;
			w[cnt] = j*y;
			z-=j;
		}
		if(z>0)
		{
			v[++cnt] = z*x;
			w[cnt] = z*y;
		}
	}
	for(int i=1;i<=cnt;i++)
	{
		if(v[i]<0)
			for(int j=-v[i];j<=m;j++)
				f[j]=max(f[j],f[j+v[i]]+w[i]);
		else
			for(int j=m; j>=v[i]; j--)
				f[j] = max(f[j], f[j-v[i]] + w[i]);
	}
	cout <<f[m];
	return 0;
}

5.二维费用背包
01背包多开一维多加一个限制条件即可。

领域展开
#include<bits/stdc++.h>
using namespace std;
const int maxn=520;
int t,m,n;
int v[maxn],w[maxn],k[maxn],f[maxn][maxn];
int main()
{
	cin >> t >> m >> n;
	for(int i=1;i<=n;i++) cin >> v[i] >> w[i] >> k[i];
	for(int i=1;i<=n;i++)
		for(int j=t;j>=v[i];j--)
			for(int l=m;l>=w[i];l--)
			f[j][l]=max(f[j][l],f[j-v[i]][l-w[i]]+k[i]);
	cout << f[t][m];
	return 0;
} 

6.分组背包

领域展开
#include<bits/stdc++.h>
using namespace std;
const int maxn=520;
int m,n,t;
int f[maxn],v[maxn][maxn],w[maxn][maxn],s[maxn];
int main()
{
	cin >> m >> n >> t;
	for(int i=1;i<=n;i++)
	{
		int x,y,z;
		cin >> x >> y >> z;
		s[z]++;
		v[z][s[z]]=x;
		w[z][s[z]]=y;
	}
	for(int i=1;i<=t;i++)	
		for(int j=m;j>=0;j--)		
			for(int k=1;k<=s[i];k++)			
				if(j>=v[i][k]&&f[j]<f[j-v[i][k]]+w[i][k])	
					f[j]=f[j-v[i][k]]+w[i][k];

	cout<<f[m];
	return 0;
}
posted @   十萧  阅读(21)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】
点击右上角即可分享
微信分享提示