传说中的动态规划dp

动态规划


动态规划有很多实例,例如:01背包问题,

01背包

一共有四样物品,你有一个背包,背包固定容量,并且物品所占一定容量,具有一定价值。
例:
现有四件物品,背包总容量为8,要求背包装价值最多的物品。

物品编号1234
物品重量2345
物品价值3458

记:f(k,w):当背包容量为w,现有k件物品可以拿,所能拿到最大价值。
f(4,8)——可拿4号,背包容量8。

  1. 拿4号物品,f(3,3)+8,可拿3号,容量3,价值得到8。
  2. 不拿4号,f(3,8),可拿3号,容量为8,价值得到零。

现存两种情况 拿与不拿;即:f(3,3)+8和f(3,8);

  1. f(3.3)+8
    3号物品重量为4,4>3,4号物品重量大于背包剩余容量,背包装不下了。所以:目前为f(2,3)+8。
    余下:拿2号和不拿2号。
    拿:f(1,0)+8+4=f(1,0)+12 再无容量 装包结束
    不拿:f(1,3)+8 继续:拿1号f(0,1)+8+3=f(0,1)+11不拿:f(0,3)+8
  2. 以此类推 进行比较取价值最大的。f(1,0)+12

f(k,w)=f(k-1,w),wk>w (物品容量大于背包剩余容量,装不下)

f(k,w)=max(f(k-1,w),f(k-1,w-wk)+vk),wk<=w(主要就是找最大的)

代码实现

板子

来源于实验室学长的传授,做题时有所改动,但大体类似。

#include<stdio.h>
#include<algorithm>
using namespace std;
#include<iostream>
#include<cstring>
#include<queue>
#define MAX 10050
#define INF 0X3f3f3f
int v[MAX], w[MAX],n,W,t,opt[MAX][MAX];
int main() {
	int t;
	while(cin>>t) {
		while(t--) {
			ciin>>n>>w;
			for(int i=1; i<=n; i++) {
				cin>>w[i];
			}
			for(int i=0; i<=n; i++) {
				cin>>w[i];
			}
			memset(opt,0,sizeof(opt));
			for(int i=1; i<=n; i++) {
				for(int j=0; j<=w; j++) {
					if(j<w[i]) {
						opt[i][j]=opt[i-1][j];
					} else {
						opt[i][j]=max(opt[i-1][j],opt[i-1][j-w[i]]+v[i]);
					}
				}
			}
			cout<<opt[n][w]<<endl;
		}
	}
	return 0;
}

此为背包plus 学长传授 灵活运用即可

#include<iostream>
#include<algorithm>
#include<string>
#include<cstdio>
#include<cstring>
#include<queue>
using namespace std;
#define INF 0x3f3f3f
#define MAX 1010


struct ITEM { //为多重背包问题结构体,便于队列优化
	int wd;
	int vd;
	ITEM (int ww, int vv) {
		wd = ww;
		vd = vv;
	}
};
queue <ITEM> items;//队列   优化多重背包
int n,W; //物种数,背包限制载荷
int w[MAX];//每种物品重量
int v[MAX];//每种物品价值
int dp[MAX][MAX];//基础价值求和表
int f[MAX];//进阶表
int num;//队列中元素个数
void OIpack ( ) {//01背包基础
	for(int i = 1; i <= n; i++) {
		for(int j = 1; j <= W; j++) {
			if( j < w[i]) {
				dp[i][j] = dp[i - 1][j];
			} else {
				dp[i][j] = max( dp[i - 1][j],dp[i - 1][j - w[i]] + v[i]);
			}
		}
	}
}
void OIPAXK ( ) { //01背包进阶
	for(int i = 1; i <=n; i++) {
		for(int j=W; j >= w[i]; j--) {
			f[j] = max( f[j], f[j - w[i]] +v[i]);
		}
	}
}
void fullpack( ) { //完全背包
	memset(f, 0, sizeof(f));//当要求价值最大且需装满时  memset (f, -INF, sizeof(f));
	for(int i = 1; i <= n; i++) {                             //
		for(int j = w[i]; j <= W; j++) {                      //
			f[j] = max(f[j], f[j - w[i]] + v[i]);             //f[j] = max(f[j], f[j - w[i]] + v[i];
		}
	}
}
void OIinit( ) {//01基础背包输入
	memset ( dp ,0, sizeof( dp));
	cin >> n >> W;
	for(int i = 1; i <= n; i++) {
		cin >> w[i] >> v[i];
	}
	return;
}
void Mulpack( ) { //多重背包
	while( !items.empty( )) {
		ITEM d=items.front( );
		for(int j = W; j >= d.wd; j--) {
			f[j] = max( f[j], f[j - d.wd] + d.vd);
		}
		items.pop( );
	}
}
void Mulinit( ) { //多重背包输入
	memset (f, 0, sizeof(f));
	num = 0;
	cin >> n >> W;
	int a, b, s;
	for(int i = 1; i <= n; i++) {
		cin >> a >> b >> s;
		ITEM x( a, b);
		for(int j = 0; j < s; j++) {
			items.push(x);
			num++;
		}
	}
}
void OIout1( ) { //输出
	cout << dp[n][W] << endl;
}
void OIout2( ) {
	cout<< f[W] <<endl;
}
int main( ) {
//	Mulinit( );
//	Mulpack( );
//	OIout2( );
	OIinit( );
	OIpack( );
	OIout1( );
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值