zoukankan      html  css  js  c++  java
  • 洛谷P4025 [PA2014]Bohater

    题目描述

    在一款电脑游戏中,你需要打败 nn 只怪物(从 11 到 nn 编号)。

    为了打败第 ii 只怪物,你需要消耗 d_idi
     点生命值,但怪物死后会掉落血药,使你恢复 a_ia
    i
     点生命值。

    任何时候你的生命值都不能降到 00(或 00 以下)。

    请问是否存在一种打怪顺序,使得你可以打完这 nn 只怪物而不死掉。

    输入格式

    第一行两个整数 n,zn,z,分别表示怪物的数量和你的初始生命值。

    接下来 nn 行,每行两个整数 d_i,a_id
    i 
    ,ai

    输出格式

    第一行为 TAK(是)或 NIE(否),表示是否存在这样的顺序。

    如果第一行为 TAK,则第二行为空格隔开的 1sim n1n 的排列,表示合法的顺序。

    如果答案有很多,你可以输出其中任意一个。(本题使用 SPJ

    输入输出样例

    输入 #1
    3 5
    3 1
    4 8
    8 3
    输出 #1
    TAK
    2 3 1 

    说明/提示

    对于 100\%100% 的数据,1le n,zle 10^51n,z10^5
    0le d_i,a_ile 10^50di,ai
    10
    ^5。

     

    思路:作为从幼儿园就开始玩游戏的我,遇到这个题心中暗喜。打怪?就这?还绿题?我不是随便切吗?既然你给我送咕值,那我就收下了。首先这很明显是一道贪心题,那么如何排序才能得到最优策略呢?首先我们按照回血量-掉血量排序,找到打他开始掉血的那个怪的编号。然后就相当于把所有的怪分成了两部分,一部分是打完他回血,另一部分是打完他掉血。很明显,当然是先打回血的才能确保是最优策略。在打回血怪的时候,可能有的怪打死他能回很多血,但是他的伤害也很高,所以我们需要先打小怪来加血,最后再去打血多的怪。我们可以这么理解,因为打回血怪一直是在回血,所以我们可以把伤害高的放到后面,这样我们就可以打完小怪恢复充足的血量再去打BOSS。感性理解一下可以证明这样打是正确的。也就是按伤害从小到大排序,然后打。好的,前半部分解决了,那么后半部分怎么办呢?我们很容易可以想到,打回血怪的时候血越打越多,那么就越有机会来杀掉最后的BOSS,所以后打BOSS。那么打掉血怪的时候,我们应该先把BOSS打掉。因为打掉血怪的时候你一直是在掉血,如果你现在不打死他,以后你血越来越少,那就更加不可能打死他了。所以这样就找到了贪心策略:先按净增加的血量排序(掉血怪是负的),打回血怪时按伤害从小到大排序,打掉血怪时按伤害从大到小排序。

    但是这样是不对的

    比如我给你一组数据,在你打完回血怪的时候你还剩11滴血,这个时候有三只掉血怪,对你造成的伤害和你打死他回复的血量分别是(8,1),(4,3),(3,2),这个顺序是我们按照贪心策略打怪的顺序,然后我们发现,在打完第一只BOSS之后,你打不死第二只怪,所以NIE。但是如果我们更改一下顺序,先打死两只小怪,这个时候你还剩9滴血,是可以再去击杀BOSS的,这样就可以打死所有的怪。这个时候我们回头想一想,我们之前的贪心策略为什么不对。

    让我们回到一开始打回血怪时贪心的本源,如果我现在可以打死小怪,我肯定不亏,因为至少我不会掉血。打回血怪时我不用去考虑到底能回多少血,因为我只要不掉血就行。只要保证一直在增加血量,我就有机会去打死伤害更高的怪。但是打掉血怪的时候不一样,我们还要考虑他们给予我们的回血。我们可以用一种整体的思路去考虑这个问题:我们的终极目标是打死所有的怪,那么也就是说,我们打掉血怪时受到的伤害总量是一定的,那么我们只要回复尽可能多的血量,就越有机会打死所有的怪。那么这个时候我们就得到了这道题的正解:掉血怪按照回血量从大到小排序。

    代码:

    #include<iostream>
    #include<cstdio>
    #include<algorithm>
    #include<cstring>
    #include<cmath>
    using namespace std;
    typedef long long int ll;
    ll n,m;
    struct guai{
        ll shang,xue,hao,zeng;//汉语拼音QWQ 
    }a[100010];
    ll cmp1(guai x,guai y){
        return x.zeng>y.zeng;
    }
    ll cmp2(guai x,guai y){
        return x.shang<y.shang;
    }
    ll cmp3(guai x,guai y){
        return x.xue>y.xue;
    }//三个阶段不同的排序 
    int main()
    {
        scanf("%lld%lld",&n,&m);
        for(int i=1;i<=n;i++){
            scanf("%lld%lld",&a[i].shang,&a[i].xue);
            a[i].zeng=a[i].xue-a[i].shang;
            a[i].hao=i;
        }
        sort(a+1,a+1+n,cmp1);//第一阶段的排序 
        int t=0;
        for(ll i=1;i<=n;i++){
            if(a[i].zeng<0){
                sort(a+1,a+i,cmp2);
                sort(a+i,a+n+1,cmp3);
                t=1;//这里有一个细节要注意一下,如果所有的怪都是回血怪,那么它里面就没有进行排序,但是实际上我们依然要按照贪心策略进行排序。所以如果里面没有排序,那么我们就到外面排一次序 
                break;
            }
        }
        if(t==0){
            sort(a+1,a+n+1,cmp2);
        }//在外面单独排序 
        for(ll i=1;i<=n;i++){
            if(m<=a[i].shang){
                printf("NIE
    ");
                return 0;
            }//如果血量小于等于0,那么结束循环同时输出不能 
            m-=a[i].shang;
            m+=a[i].xue;
        }
        printf("TAK
    ");
        for(ll i=1;i<=n;i++){
            printf("%d ",a[i].hao);//可以的话输出编号 
        }
        return 0;
    }

    最后,不要忘记开longlong(10^5*10^5=10^10会爆int)

  • 相关阅读:
    vuex 入门
    Vuex 原理
    java web开发问题集合
    JSP Servlet 路径解析 路径设置
    随笔——学习的一些步骤及注意点(不断更新)
    常用正则表达式大全!(例如:匹配中文、匹配html)
    myeclipse+tomcat 工程名改名的问题 ——————完美解决方案
    web开发的步骤
    Servlet中的GET和POST之间的区别
    html、css、javascript、JSP 、xml学习顺序应该是怎样的呢?
  • 原文地址:https://www.cnblogs.com/57xmz/p/13293264.html
Copyright © 2011-2022 走看看