HDU 6082 度度熊与邪恶大魔王 (DP)

Description

度度熊为了拯救可爱的公主,于是与邪恶大魔王战斗起来。
邪恶大魔王的麾下有\(n\)个怪兽,每个怪兽有\(a[i]\)的生命值,以及\(b[i]\)的防御力。
度度熊一共拥有\(m\)种攻击方式,第\(i\)种攻击方式,需要消耗\(k[i]\)的晶石,造成\(p[i]\)点伤害。
当然,如果度度熊使用第\(i\)个技能打在第\(j\)个怪兽上面的话,会使得第\(j\)个怪兽的生命值减少\(p[i]-b[j]\),当然如果伤害小于防御,那么攻击就不会奏效。
如果怪兽的生命值降为\(0\)或以下,那么怪兽就会被消灭。
当然每个技能都可以使用无限次。
请问度度熊最少携带多少晶石,就可以消灭所有的怪兽。

Input

本题包含若干组测试数据。
第一行两个整数\(n\)\(m\),表示有\(n\)个怪兽,\(m\)种技能。
接下来\(n\)行,每行两个整数,\(a[i]\)\(b[i]\),分别表示怪兽的生命值和防御力。
再接下来\(m\)行,每行两个整数\(k[i]\)\(p[i]\),分别表示技能的消耗晶石数目和技能的伤害值。
数据范围:\(1 \leqslant n \leqslant 100000\)\(1 \leqslant m \leqslant 1000\)\(1 \leqslant a[i] \leqslant 1000\)\(0 \leqslant b[i] \leqslant 10\)\(0 \leqslant k[i] \leqslant 100000\)\(0 \leqslant p[i] \leqslant 1000\)

Output

对于每组测试数据,输出最小的晶石消耗数量,如果不能击败所有的怪兽,输出-1。

Sample Input

1 2
3 5
7 10
6 8
1 2
3 5
10 7
8 6

Sample Output

6
18

Solution

读完题首先一定会想到用贪心,对于每种怪物,选能造成伤害的即能当中性价比最高的去攻击。但马上就会发现,当怪物的剩余的生命值小于一次攻击造成的伤害的时候,最高性价比的攻击可能就不是最优策略了。

稍做分析就会发现,这其实是一个背包模型,\(m\)种技能对应\(m\)件物品,每种技能都有价值和花费,每个怪物的生命值是价值的下限。现在问题转化为\(m\)种物品,每种都可以取无穷多个,要在总价值大于等于下限的条件下让总花费尽量少。完全背包的变形。

由于怪物的防御力最大只有\(10\),考虑枚举防御力,此时的攻击力减防御力就是物品的价值。对于个防御力值进行一遍DP。

设共有\(n\)只怪物,怪物的生命值最大为\(maxa\)\(p[i]\)为第\(i\)种技能的攻击力,\(c[i]\)为第\(i\)种技能的花费。

状态\(dp[k][i][j]\)表示防御力为\(k\),用前\(i\)个技能使攻击值大于等于\(j\)时的最小花费。
转移

\[dp[k][i][j]= \begin{cases} dp[k][i-1][j], &p[i]-k \leqslant 0\\ \min\{dp[k][i-1][j],dp[k][i][max(j-p[i]+k,0)]\}, &p[i]-k > 0 \end{cases} \]

初始\(dp[k][i][0] = 0, 0 \leqslant i \leqslant m\)\(dp[k][0][j] = \infty, 1 \leqslant j \leqslant maxa\)
目标\(\sum_{i=1}^{n}{dp[b[i]][m][a[i]]}\)

由于内存和时间的限制,可以把dp数组的第一维去掉,还可以考虑将n只怪物按防御力从小到大排序。

Code

#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
typedef long long ll;
const int INF = 0x3f3f3f3f;
const int N = 1e5 + 5;

struct Tuple
{
    int a, b;
} t[N];
int p[1001], c[1001];
int dp[1001][1001];

bool cmp(Tuple &a, Tuple &b)
{
    return a.b < b.b;
}

int main()
{
    int n, m;
    while (~scanf("%d%d", &n, &m))
    {
        for (int i = 1; i <= n; i++) scanf("%d%d", &t[i].a, &t[i].b);
        sort(t + 1, t + n + 1, cmp);
        for (int i = 1; i <= m; i++) scanf("%d%d", c + i, p + i);
        int l = 1;
        ll ans = 0;
        bool flag = false;
        while (l <= n)
        {
            int k = t[l].b;
            int r = l + 1;
            while (r <= n && t[r].b == k) r++;
            int maxa = 0;
            for (int i = l; i < r; i++) maxa = max(maxa, t[i].a);
            for (int j = 1; j <= maxa; j++) dp[0][j] = INF;
            for (int i = 0; i <= m; i++) dp[i][0] = 0;
            for (int i = 1; i <= m; i++)
                for (int j = 1; j <= maxa; j++)
                {
                    dp[i][j] = dp[i - 1][j];
                    if (p[i] - k > 0) dp[i][j] = min(dp[i][j], dp[i][max(j - p[i] + k, 0)] + c[i]);
                }
            for (int i = l; i < r; i++)
            {
                if (dp[m][t[i].a] == INF) { flag = true; break; }
                ans += dp[m][t[i].a];
            }
            if (flag) break;
            l = r;
        }
        if (flag) printf("-1\n");
        else printf("%I64d\n", ans);
    }
    return 0;
}

http://acm.hdu.edu.cn/showproblem.php?pid=6082

posted @ 2017-08-06 19:29  达达Mr_X  阅读(276)  评论(0编辑  收藏  举报