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

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qq1965610770/article/details/76769182

Problem 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<=n<=100000

1<=m<=1000

1<=a[i]<=1000

0<=b[i]<=10

0<=k[i]<=100000

0<=p[i]<=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

题解:

        参照 0/1背包 DP。

注意事项:

        晶石取值范围为10^13内;

        一堆怪中有一只全技能未破防;

        存在0消耗的技能;


#include<iostream>
#include<cstdio>
#include<algorithm>
#include<vector>
using namespace std;
typedef long long ll;
struct skill{
    int use;
    int atk;
};
ll fight(vector<int> &em,int def,vector<skill> my);
int main()
{
    int n,m;
    while(~scanf("%d%d",&n,&m))
    {
        int t,t1;
        vector<vector<int> > em(11);
        vector<skill> my(m);
        for(t=0;t<n;t++)			/*以防御值划分怪兽*/
        {
            int hp,def;
            scanf("%d%d",&hp,&def);
            em[def].push_back(hp);
        }
        for(t=0;t<m;t++)
            scanf("%d%d",&my[t].use,&my[t].atk);
        ll s=0;
        t = t1 = 0;
        for(t=10;t>=0;t--)		/*由高防怪开始统计,尽早判断 "-1" 情况*/
        {
            if(em[t].size() == 0)
                continue;
            ll j = fight(em[t],t,my);
            if(j == -1)
                break;
            s += j;
        }
        if(t != -1)
            printf("-1\n");
        else
            printf("%lld\n",s);
    }
    return 0;
}
ll fight(vector<int> &em,int def,vector<skill> my)
{
    int t;
    ll s=0;
    for(t=0;t<my.size();t++)		/*取得各技能实际伤害*/
    {
        if(my[t].atk > def)
            my[t].atk -= def;
        else
            my[t].atk = 0;
    }
    int n;
    n = my.size();
    for(t=0;t<n;t++)			/*将0伤害技能排除*/ 
    {
        if(my[t].atk == 0)
        {
            skill ex;
            ex = my[t];
            my[t] = my[n-1];
            my[n-1] = ex;
            n--;
            t--;
        }
    }
    if(n == 0)
        return -1;
    vector<vector<ll> > dp(n+1);		/* 0/1背包思路,dp[n]储存每列的最少(圣)晶石消耗*/
    int hpm = 0;						/*其中,行代表怪物的 hp 由 1 到 maxhp,列代表各技能的使用*/ 
    for(t=0;t<em.size();t++)
    {
        if(hpm < em[t])
            hpm = em[t];
    }
    for(t=0;t<=n;t++)
    {
        vector<ll> dp2(hpm+1,0);
        dp[t] = dp2;
    }
    for(t=1;t<=hpm;t++)
    {
        int t1;
        int m = 0x3f3f3f3f;
        for(t1=0;t1<n;t1++)
        {
            if(my[t1].atk >= t)
                dp[t1][t] = my[t1].use;
            else
                dp[t1][t] = my[t1].use+dp[n][t-my[t1].atk];
            if(m > dp[t1][t])
                m = dp[t1][t];
        }
        dp[n][t] = m;
    }
    for(t=0;t<em.size();t++)
        s += dp[n][em[t]];
    return s;
}



猜你喜欢

转载自blog.csdn.net/qq1965610770/article/details/76769182