一本通1267:【例9.11】01背包問題 (淺談01背包問題)


原題傳送門

一道01背包入門 & 模板題,以下主要提供兩種思路

\(Solution\ 1\)

看到這道題,首先想到的就是用二維數組來\(DP\)

狀態的表示:\(f[i][j]\)表示前\(i\)個總重量不超過\(j\)的最大價值

狀態的轉移:\(f[i][j]=max(f[i-1][j],f[i-1][j-w[i]]+c[i])\ (w[i]<=j)\)
注:\(w[i]\)表示第\(i\)個物品的重量,\(c[i]\)表示第\(i\)個物品的價值,\(j\)表示當前的最大重量

最優解:\(f[n][m]\)
注:\(n\)指物體數量,\(m\)指最大重量

\(Code\)

#include<iostream>
#include<cstdio>
#include<string>
using namespace std;
inline void read(int &x){
	int f=1;
	char ch=getchar();
	x=0;
	while(ch<'0'||ch>'9'){
		if(ch=='-') f=-1;
		ch=getchar();
	}
	while(ch>='0'&&ch<='9'){
		x=x*10+ch-'0';
		ch=getchar();
	}
	x*=f;
}
int m,n;
int f[201][201]={0};
int w[31],c[31];
int main(){
	read(m);read(n);
	for(int i=1;i<=n;i++){
		read(w[i]);
		read(c[i]);
	}
	for(int i=1;i<=n;i++){      //當前物體編號
		for(int j=m;j>0;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[n][m]);
	return 0;
}

\(Solution\ 2\)

顯然,二維數組的空間占用非常大。如果背包的最大空間再大一些,就會喜提\(MLE\)的好成績

那就有一種新的方法:

狀態的表示:\(f[j]\)表示不超過\(j\)重量的最大價值

狀態的轉移:\(f[j]=max(f[j],f[j-w[i]]+c[i])\)
注:\(i\)依然表示物品編號

最優解:\(f[m]\)
注:\(m\)表示最大重量

\(Code\)

#include<iostream>
#include<cstdio>
#include<string>
using namespace std;
inline void read(int &x){
	int f=1;
	char ch=getchar();
	x=0;
	while(ch<'0'||ch>'9'){
		if(ch=='-') f=-1;
		ch=getchar();
	}
	while(ch>='0'&&ch<='9'){
		x=x*10+ch-'0';
		ch=getchar();
	}
	x*=f;
}
#include<iostream>
#include<cstdio>
#include<string>
using namespace std;
inline void read(int &x){
	int f=1;
	char ch=getchar();
	x=0;
	while(ch<'0'||ch>'9'){
		if(ch=='-') f=-1;
		ch=getchar();
	}
	while(ch>='0'&&ch<='9'){
		x=x*10+ch-'0';
		ch=getchar();
	}
	x*=f;
}
int m,n;
int f[201]={0};
int w[31],c[31];
int main(){
	read(m);read(n);
	for(int i=1;i<=n;i++){
		read(w[i]);
		read(c[i]);
	}
	for(int i=1;i<=n;i++){
		for(int j=m;j>=w[i];j--){	//j>=w[i]保證一定能裝下
			f[j]=max(f[j],f[j-w[i]]+c[i]); 
		}
	}
	printf("%d",f[m]);
	return 0;
}

看到最后,可能會有一個問題:為什么需要倒序循環?
觀察狀態轉移方程:\(f[i][j]=max(f[i-1][j],f[i-1][j-w[i]]+c[i])\ (w[i]<=j)\)
\(f[i][j]\)的值只與上一行的值\(f[i-1][]\)有關
更新的時候需要用到舊值,倒序防止循環被覆蓋。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM