HDU 2159 DP

因爲題目是中文題,那麼在此就不再描述。大意是一個人需要N的經驗升級,身上的初始忍耐度爲M,怪有K種,其中給出殺每種怪給的經驗和消耗的忍耐度,已知最多殺怪S只,文能否升級,如果能的話,最大剩餘忍耐度是多少。

題目分析:我們可以把這個問題轉化成一個揹包問題,dp[i][j][k]表示前i個怪種,消耗的忍耐度爲j,選中的怪的數量爲k所獲得的最大經驗值。並且我們可以通過滾動數組來節省空間用dp[j][k]表示打K個怪消耗忍耐度爲J獲得的最大經驗。

於是這個題就可以轉變成我們熟悉的揹包問題:

如下代碼(附帶註釋):

#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
#define N 110 
using namespace std;
int dp[N][N];//dp[j][k]表示打k個怪,消耗忍耐度爲j所獲得的最大經驗 
int main()
{
	int n,m,K,s;
	int v[N],w[N];
	while(scanf("%d%d%d%d",&n,&m,&K,&s)!=EOF)
	{
		for(int i=1;i<=K;i++)
			scanf("%d%d",&w[i],&v[i]);
		memset(dp,0,sizeof(dp));
		int ans=-1;//初始化 
		bool flag=false;//標記 
		for(int j=1;j<=m;j++)//忍耐度 
		{
			for(int i=1;i<=K;i++)//怪物的種類 即爲我們空間優化掉的i 
			{
				for(int k=1;k<=s;k++)//打得怪的數量 
				{
					for(int x=0;x<=k&&x*v[i]<=j;x++)//多重集 
					{
						dp[j][k]=max(dp[j][k],dp[j-x*v[i]][k-x]+x*w[i]);//狀態轉移方程 
						if(dp[j][k]>=n)
						{
							flag=true;
							ans=j;
							break;
						}	
					}
					if(flag)
						break;	
				}
				if(flag)
					break;
			}
			if(flag)
				break;	
		}
		if(flag)
		cout<<m-ans<<endl;
		else
		cout<<"-1"<<endl;
	}		
	//while(1);
	return 0; 
}


發佈了51 篇原創文章 · 獲贊 0 · 訪問量 2萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章