因为题目是中文题,那么在此就不再描述。大意是一个人需要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;
}