因爲題目是中文題,那麼在此就不再描述。大意是一個人需要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;
}