HDU2159 FATE(二维背包、带限制条件的背包问题)

题目传送门

 

题意很明显,就不细说了

 

我们这里可以把剩下的忍耐度看作背包容量,然后价值就是杀了怪所得的经验

用第二维表示杀了q只怪,这样就能用dp[j][q]表示已消耗j点忍耐度,杀了q只怪时的经验值

状态转移方程dp[j][q] = max(dp[j][q],dp[j-b[i]][q-1]+a[i])

a[i]表示杀死i怪物所获得的经验

b[i]表示杀死i怪物所消耗的忍耐值

对于第i个怪物:

                (1)杀:此时我们消耗j-b[i]点忍耐度,同时击杀怪物数+1,并且获得a[i]点经验

                 (2)不杀:此时我们忍耐度不变,击杀怪物数不变,由于空间已经优化到二维,所以有dp[j][q]=dp[j][q]

综合即为上述状态转移方程

 

代码如下:

#include <iostream>
#include <cstdio>
#include <string>
#include <cstring>
#include <cmath>
#include <algorithm>
#define For(a,b) for(int a=0;a<b;a++)
#define mem(a,b) memset(a,b,sizeof(a))
using namespace std;
typedef long long ll;
const int maxn =  1e2+10;
const int INF = 0x3f3f3f3f;
const int inf = 0x3f;
const double EPS = 1e-7;
const int MOD = 1e9+7;
int dp[maxn][maxn];
int a[maxn];
int b[maxn];
int n,m,k,s;
int main()
{
    while(cin >> n >> m >> k >> s){
        mem(dp,0);
        For(i,k)
            cin >> a[i+1] >> b[i+1];
        for(int i=1;i<=k;i++)
            for(int j=b[i];j<=m;j++)
                for(int q=1;q<=s;q++)
                   dp[j][q] = max(dp[j][q],dp[j-b[i]][q-1]+a[i]);
        int ans = -1;
        for(int j=1;j<=m;j++)    //从小->大寻找,满足所需经验就break
            if(dp[j][s]>=n){
                ans = m-j;
                break;
            }
        cout << ans<<endl;
    }
    return 0;
}

 

posted @ 2018-07-19 17:12  秃头大师  阅读(682)  评论(0编辑  收藏  举报