1. 程式人生 > >0-1揹包模板

0-1揹包模板

#1038 : 01揹包

時間限制:20000ms

單點時限:1000ms

記憶體限制:256MB

描述

且說上一週的故事裡,小Hi和小Ho費勁心思終於拿到了茫茫多的獎券!而現在,終於到了小Ho領取獎勵的時刻了!

小Ho現在手上有M張獎券,而獎品區有N件獎品,分別標號為1到N,其中第i件獎品需要need(i)張獎券進行兌換,同時也只能兌換一次,為了使得辛苦得到的獎券不白白浪費,小Ho給每件獎品都評了分,其中第i件獎品的評分值為value(i),表示他對這件獎品的喜好值。現在他想知道,憑藉他手上的這些獎券,可以換到哪些獎品,使得這些獎品的喜好值之和能夠最大。

提示一:合理抽象問題、定義狀態是動態規劃最關鍵的一步

提示二:說過了減少時間消耗,我們再來看看如何減少空間消耗

輸入

每個測試點(輸入檔案)有且僅有一組測試資料。

每組測試資料的第一行為兩個正整數N和M,表示獎品的個數,以及小Ho手中的獎券數。

接下來的n行描述每一行描述一個獎品,其中第i行為兩個整數need(i)和value(i),意義如前文所述。

測試資料保證

對於100%的資料,N的值不超過500,M的值不超過10^5

對於100%的資料,need(i)不超過2*10^5, value(i)不超過10^3

輸出

對於每組測試資料,輸出一個整數Ans,表示小Ho可以獲得的總喜好值。

樣例輸入

5 1000
144 990
487 436
210 673
567 58
1056 897

樣例輸出

2099

題目來源:https://hihocoder.com/problemset/problem/1038

哎嘿,終於要更新這個01揹包了,2018下半年學期開始就說要搞這個01揹包,奈何看不懂一直在擱置,現在在刷紫書的動態規劃專題,做了硬幣問題,發現我會寫這個題了。直接貼AC程式碼

就是一個從起點m到0的最長路徑。之前那個矩形的巢狀是沒有起點和終點所以採用記憶化搜尋,當然排序之後也就是有起點和終點了。

#include<cstdio>
#include<cstring>
using namespace std;
const int maxn=1e5+10;
int dp[maxn];
int v[1005],w[2*maxn];
int main()
{
	int n,m;
	while(~scanf("%d%d",&n,&m))
	{
		for(int i=1;i<=n;i++) scanf("%d%d",&w[i],&v[i]);
		memset(dp,0,sizeof(dp));
		for(int i=1;i<=n;i++)//列舉每個物品,可輕鬆訪問w[i],v[i] 
		{
			for(int k=m;k>=w[i];k--)//k 就是狀態 ,k從m開始往下減的目的呢就是假設 每個狀態k由 k-w[i]組成 
			{//這樣就可以儲存第i個物品所貢獻的最大v[i]值,也就是題目的幸福值。 
			//然後不斷的遍歷物品更新狀態dp[k]的最大值,就可以得到答案了 
				if(dp[k]<dp[k-w[i]]+v[i]) dp[k]=dp[k-w[i]]+v[i];//狀態轉移方程 
			} 
		}
		printf("%d\n",dp[m]);
	}
}