动态规划专题

前言

太恐怖了,今天一复习动态规划,才发现我什么都不会,0/1背包都打不出来,还学什么斜率优化DP,四边形不等式DP,学个喘喘,so scary,到头来发现自己是小白,啥都不会啊!!!

所以,没有时间在等了,必须立刻安排复习

0/1 背包问题

http://oi.cdshishi.net/p/A1031

题目大意

\(n\) 个物体,背包大小为 \(m\),每个物体有一个大小 \(w[i]\),有一个价值 \(c[i]\),现在求背包里能装下的最大价值。

做题思路

动态规划数组 \(f[ i ][ j ]\) 表示装了 \(i\) 个物品,背包大小为 \(j\) 时的最大价值。

考虑如何转移:

\[f[i][j]=\max(f[i-1][j],f[i-1][j-w[i]]+c[i]) \]

即比较不装第 \(i\) 个物品和装第 \(i\) 个物品哪个贡献大,如果当前背包空间小于 \(w[i]\) (也就是装不下这个物品)那就不装。

最后答案在 \(f[n][m]\) 里面。

AC 代码

#include<bits/stdc++.h>
using namespace std;
int n,m,f[2000][2000];
int w[2000],c[2000];
int main(){
	scanf("%d%d",&m,&n);
	for(int i=1;i<=n;i++){
		scanf("%d%d",&w[i],&c[i]);
	}
	for(int i=1;i<=n;i++){
		for(int j=1;j<=m;j++){
			if(j>=w[i]){
				f[i][j]=max(f[i-1][j],f[i-1][j-w[i]]+c[i]);
			}
			else f[i][j]=f[i-1][j];
		}
	}
	printf("%d",f[n][m]);
	return 0;
}

完全背包

在前行中认可自己,证明自己!

题目大意

相比于0/1背包只能选一个物体,完全背包的区别是每个物体有无数多个,给定背包大小,问能装下的最大价值。

做题思路

瞎做法: 开始自己沿着0/1背包的思路乱写了一个,没想到竟然A了,但空间和时间复杂度都没有正解优,时间复杂度应该是 \(O(nm^2)\),无奈这题 \(n,m\) 都只有200,所以过了,

正解思路: 只需要在0/1背包的代码上改动一个地方即可,即转移时如果选当前物体,还是从选到了 \(i\) 的这一当前层迭代,这样就达到了同一个物体选多次的目的了。

\[f[i][j]=\max(f[i-1][j],f[i][j-w[i]]+c[i]) \]

我只能说动态规划太奇妙,你可以盯着它的转移方程式半个小时也证不出它是正确的。(哭:

瞎搞核心代码:

for(int i=1;i<=n;i++){
		for(int k=1;k*w[i]<=m;k++){
			++cnt;
			for(int j=1;j<=m;j++){
				if(j>=w[i]){
					f[cnt][j]=max(f[cnt-1][j],f[cnt-1][j-w[i]]+c[i]);
				}
				else f[cnt][j]=f[cnt-1][j];
				ans=max(ans,f[cnt][j]);
			}
		}
	}

正解代码:

	for(int i=1;i<=n;i++){
		for(int j=1;j<=m;j++){
			if(w[i]<=j){
				f[i][j]=max(f[i-1][j],f[i][j-w[i]]+c[i]); 
			}
			else f[i][j]=f[i-1][j];
		}
	}

多重背包

题目大意

与上面不同的是,这次物品数量既不是一个,又不是无穷个,而是给定个。

做题思路

完了,什么玩意儿!啥啥二进制优化,让我好好研究一下。

好的,研究完了,十分的简单,就是把个数拆解成 \(1,2,4,8,16,32,64.....\) 的二进制倍数,这样任意组合即可组合出 \([1,x]\) 中的任意数,剩下的按0/1背包做就行。

核心代码:

	for(int j=1;j<=n;j++){
		int wi,ci,x;
		scanf("%d%d%d",&wi,&ci,&x);
		for(int i=1;i<=x;i=(i<<1)){
			x-=i;
			w[++cnt]=i*wi;
			c[cnt]=i*ci;
		}
		if(x){
			w[++cnt]=x*wi;
			c[cnt]=x*ci;
		}
	}
	for(int i=1;i<=cnt;i++){
		for(int j=1;j<=m;j++){
			if(w[i]<=j){
				f[i][j]=max(f[i-1][j],f[i-1][j-w[i]]+c[i]);
			}
			else{
				f[i][j]=f[i-1][j];
			}
		}
	}
	printf("%d",f[cnt][m]);

背包问题到这里就基本结束了,是时候开始下一个专题了。

到时候补充一下把空间优化到一维的方法。

posted @ 2023-07-25 11:16  alloverzyt  阅读(7)  评论(0编辑  收藏  举报