1. 程式人生 > >HDU2159 FATE【二維費用揹包+完全揹包】

HDU2159 FATE【二維費用揹包+完全揹包】

FATE

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 19336    Accepted Submission(s): 9093


 

Problem Description

最近xhd正在玩一款叫做FATE的遊戲,為了得到極品裝備,xhd在不停的殺怪做任務。久而久之xhd開始對殺怪產生的厭惡感,但又不得不通過殺怪來升完這最後一級。現在的問題是,xhd升掉最後一級還需n的經驗值,xhd還留有m的忍耐度,每殺一個怪xhd會得到相應的經驗,並減掉相應的忍耐度。當忍耐度降到0或者0以下時,xhd就不會玩這遊戲。xhd還說了他最多隻殺s只怪。請問他能升掉這最後一級嗎?

Input

輸入資料有多組,對於每組資料第一行輸入n,m,k,s(0 < n,m,k,s < 100)四個正整數。分別表示還需的經驗值,保留的忍耐度,怪的種數和最多的殺怪數。接下來輸入k行資料。每行資料輸入兩個正整數a,b(0 < a,b < 20);分別表示殺掉一隻這種怪xhd會得到的經驗值和會減掉的忍耐度。(每種怪都有無數個)

Output

輸出升完這級還能保留的最大忍耐度,如果無法升完這級輸出-1。

Sample Input

10 10 1 10
1 1
10 10 1 9
1 1
9 10 2 10
1 1
2 2

Sample Output

0
-1
1

Author

Xhd

Source

2008資訊工程學院集訓隊——選拔賽

問題連結:HDU2159 FATE

解題思路:二維費用揹包+完全揹包。dp[i][j]表示忍耐度為i殺j只怪所能獲得的最大經驗值 。具體看程式

AC的C++程式碼:

#include<iostream>
#include<algorithm>
#include<cstring>

using namespace std;

const int N=105;
const int INF=100000;
int dp[N][N],a[N],b[N];//dp[i][j]表示忍耐度為i殺j只怪所能獲得的最大經驗值 

int main()
{
	int n,m,k,s;
	while(~scanf("%d%d%d%d",&n,&m,&k,&s)){
		for(int i=0;i<k;i++)
		  scanf("%d%d",&a[i],&b[i]);//得到的經驗值和會減掉的忍耐度
		
		int res=INF;
		memset(dp,0,sizeof(dp));
		for(int i=0;i<k;i++)//遍歷k只怪物 
		  for(int j=b[i];j<=m;j++)//忍耐度為j 
		    for(int t=1;t<=s;t++){//殺t只怪 
		      	dp[j][t]=max(dp[j][t],dp[j-b[i]][t-1]+a[i]);
		      	if(dp[j][t]>=n)
		      	  res=min(res,j);
			  }
		if(res>m)
		  printf("-1\n");
		else
		  printf("%d\n",m-res);
	}
	return 0;
}
 

換一種思路,但是發現提交後WA

#include<iostream>
#include<algorithm>
#include<cstring>

using namespace std;

const int N=105;
const int INF=10000;
int dp[N][N],a[N],b[N];//dp[i][j]表示殺i只怪,獲得j經驗值需要消耗的最少忍耐度 

int main()
{
	int n,m,k,s;
	while(~scanf("%d%d%d%d",&n,&m,&k,&s)){
		for(int i=0;i<k;i++)
		  scanf("%d%d",&a[i],&b[i]);//得到的經驗值和會減掉的忍耐度
		for(int i=0;i<N;i++)
		  for(int j=0;j<N;j++)
		    dp[i][j]=INF;
		dp[0][0]=0;//殺0只怪只能獲得0經驗值,所需的最少忍耐度也為0
		
		for(int i=0;i<k;i++)//遍歷k只怪物 
		  for(int j=1;j<=s;j++)//殺j只怪物 
		    for(int t=a[i];t<=n;t++)//獲得t經驗值 
		      dp[j][t]=min(dp[j][t],dp[j-1][t-a[i]]+b[i]);
		
		int res=INF;
		for(int i=0;i<=s;i++)//尋找獲得經驗值n,殺小於等於s只怪所需的最少忍耐度 
		  res=min(dp[i][n],res);
		m-=res;
		if(m<0) m=-1;
		printf("%d\n",m);
	}
	return 0;
}