把忍耐值和杀怪数当成两个背包
dp[i][j]表示忍耐值为i,杀怪数为j时的经验
dp[i][j]=max( dp[i][j], dp[i-b[i]][j-1]+a[i]);
显然,它只是要求杀怪数不超过s,那么dp[i][s],肯定是消耗忍耐值为i时,获得的最大经验了
所以从小到大枚举忍耐值m,当dp[i][s]>=n时,就break,保证了得出答案时m是较小的
#include <iostream>
#include <stdio.h>
#include <algorithm>
#include <string.h>
using namespace std;
int main()
{
int n,m,k,s,a[102],b[102];
int dp[102][102],x,y,z;
while(~scanf("%d%d%d%d",&n,&m,&k,&s))
{
for(int i=0;i<k;i++) scanf("%d%d",&a[i],&b[i]);
memset(dp,0,sizeof(dp));
for(x=1;x<=m;x++)
{
for(y=0;y<k;y++)
{
for(z=1;z<=s;z++)
{
int c=0;
while(c<=z && c*b[y]<=x)
{
dp[x][z]=max(dp[x][z],dp[x-c*b[y]][z-c]+c*a[y]);
c++;
}
}
}
if(dp[x][s]>=n) break;
}
if(x>m) printf("-1\n");
else printf("%d\n",m-x);
}
return 0;
}