【DP】HDU-3008 Warcraft

69 篇文章 0 订阅

Warcraft

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)

Problem Description
Have you ever played the Warcraft?It doesn't matter whether you have played it !We will give you such an experience.There are so many Heroes in it,but you could only choose one of them.Each Hero has his own skills.When such a Skill is used ,it costs some MagicValue,but hurts the Boss at the same time.Using the skills needs intellegence,one should hurt the enemy to the most when using certain MagicValue.

Now we send you to complete such a duty to kill the Boss(So cool~~).To simplify the problem:you can assume the LifeValue of the monster is 100, your LifeValue is 100,but you have also a 100 MagicValue!You can choose to use the ordinary Attack(which doesn't cost MagicValue),or a certain skill(in condition that you own this skill and the MagicValue you have at that time is no less than the skill costs),there is no free lunch so that you should pay certain MagicValue after you use one skill!But we are good enough to offer you a "ResumingCirclet"(with which you can resume the MagicValue each seconds),But you can't own more than 100 MagicValue and resuming MagicValue is always after you attack.The Boss is cruel , be careful!
 

Input
There are several test cases,intergers n ,t and q (0<n<=100,1<=t<=5,q>0) in the first line which mean you own n kinds of skills ,and the "ResumingCirclet" helps you resume t points of MagicValue per second and q is of course the hurt points of LifeValue the Boss attack you each time(we assume when fighting in a second the attack you show is before the Boss).Then n lines follow,each has 2 intergers ai and bi(0<ai,bi<=100).which means using i skill costs you ai MagicValue and costs the Boss bi LifeValue.The last case is n=t=q=0.
 

Output
Output an interger min (the minimun time you need to kill the Boss)in one line .But if you die(the LifeValue is no more than 0) ,output "My god"!
 

Sample Input
  
  
4 2 25 10 5 20 10 30 28 76 70 4 2 25 10 5 20 10 30 28 77 70 0 0 0
 

Sample Output
  
  
4 My god
Hint
Hint: When fighting,you can only choose one kind of skill or just to use the ordinary attack in the whole second,the ordinary attack costs the Boss 1 points of LifeValue,the Boss can only use ordinary attack which costs a whole second at a time.Good Luck To You!
 
————————————————————————————————————————————————————————
题意:有n个技能,每个技能消耗魔法ai,造成伤害bi。自己和boss的血量都为100。boss每秒造成伤害q。自己魔法初始值为100,每秒回复t。普通攻击不消耗魔法,只造成1点伤害。问杀死boss的最短时间,如果不能,则输出My god。
思路:首先因为boss每秒伤害固定,自己又不能回复血量所以自己存活的最大时间是固定的。
将每秒当做一个回合。题目说了“we assume when fighting in a second the attack you show is before the Boss”。所以每回合自己先放技能。
1. 状态描述:第几回合、boss当前血量、当前剩余魔法值
2. 最优子结构:对于每一回合、boss血量确定的时候,剩余魔法值是越多越好;换言之,对于每一回合、剩余魔法值确定的时候,boss的血量越少越好。这两种情况都可以做,但是实现起来却不一样。
3. 决策:如果计算boss血量,那么MP值会作为下标,这个时候MP值和回合是有相互影响的,(MP回复),因此不能省略回合这一维。如果计算MP值,那么boss血量为下标,这个时候就可以省略第一维。枚举技能决定是否更新。
给出两种代码:
计算boss血量:
/**
 * ID: j.sure.1
 * PROG:
 * LANG: C++
 */
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <algorithm>
#include <ctime>
#include <cmath>
#include <stack>
#include <queue>
#include <vector>
#include <map>
#include <set>
#include <string>
#include <climits>
#include <iostream>
#define Mem(f, x) memset(f, x, sizeof(f))
#define Pb push_back
#define LL long long
using namespace std;
const int INF = 0x3f3f3f3f;
const double eps = 1e-8;
/****************************************/
const int N = 105;
int n, t, q, lim;
int hurt[N], cost[N], dp[N][N];

int Ceil(int x, int y)
{
    double a = 1.0*x / y;
    if(a - (int)a > eps) {
        return (int)a + 1;
    }
    return (int)a;
}

int main()
{
#ifdef J_Sure
    freopen("000.in", "r", stdin);
    //freopen("999.out", "w", stdout);
#endif
    while(scanf("%d%d%d", &n, &t, &q), n||t||q) {
        lim = Ceil(100, q);//存活时间
        for(int i = 0; i < n; i++) {
            scanf("%d%d", &cost[i], &hurt[i]);
        }
        cost[n] = 0; hurt[n] = 1;
        Mem(dp, 0x3f);
        dp[0][100] = 100;
        bool ok = false;
        for(int i = 1; i <= lim; i++) {
            for(int j = 100; j >= 0; j--) {
                for(int k = 0; k <= n; k++) if(j+cost[k]<=100 && dp[i-1][j+cost[k]] != INF) {
                    int jj = j + t > 100 ? 100 : j + t;
                    dp[i][jj] = min(dp[i][jj], dp[i-1][j+cost[k]] - hurt[k]);
                    if(dp[i][jj] <= 0) {
                        printf("%d\n", i);
                        ok = true;
                        break;
                    }
                }
                if(ok) break;
            }
            if(ok) break;
        }
        if(!ok) puts("My god");
    }
    return 0;
}

计算MP值:
/**
 * ID: j.sure.1
 * PROG:
 * LANG: C++
 */
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <algorithm>
#include <ctime>
#include <cmath>
#include <stack>
#include <queue>
#include <vector>
#include <map>
#include <set>
#include <string>
#include <climits>
#include <iostream>
#define Mem(f, x) memset(f, x, sizeof(f))
#define Pb push_back
#define LL long long
using namespace std;
const int INF = 0x3f3f3f3f;
const double eps = 1e-8;
/****************************************/
const int N = 105;
int n, t, q, lim;
int hurt[N], cost[N], dp[N];

int Ceil(int x, int y)
{
    double a = 1.0*x / y;
    if(a - (int)a > eps) {
        return (int)a + 1;
    }
    return (int)a;
}

int main()
{
#ifdef J_Sure
    freopen("000.in", "r", stdin);
    //freopen("999.out", "w", stdout);
#endif
    while(scanf("%d%d%d", &n, &t, &q), n||t||q) {
        lim = Ceil(100, q);//存活时间
        for(int i = 0; i < n; i++) {
            scanf("%d%d", &cost[i], &hurt[i]);
        }
        cost[n] = 0; hurt[n] = 1;
        Mem(dp, -1);
        dp[100] = 100;
        bool ok = false;
        for(int i = 1; i <= lim; i++) {//限制:不能死
            for(int j = 0; j <= 100; j++) if(~dp[j]) {//限制:该状态已计算过
                for(int k = 0; k <= n; k++) if(dp[j] - cost[k] >= 0) {//限制:MP足够
                    if(j <= hurt[k]) {//限制:boss的血量非负,否则就得到解了
                        printf("%d\n", i);
                        ok = true;
                        break;
                    }
                    dp[j-hurt[k]] = max(dp[j-hurt[k]], dp[j]-cost[k]+t > 100 ? 100 : dp[j]-cost[k]+t);
                }
                if(ok) break;
            }
            if(ok) break;
        }
        if(!ok) puts("My god");
    }
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值