• HDU 4415 Assassin's Creed(贪心)


    HDU 4415

    题意:

    壮哉我Assassin!


    E叔有一柄耐久度为m的袖剑,以及n个目标士兵要去解决。
    每解决掉一个士兵,消耗袖剑Ai的耐久度。且获得该士兵的武器,能够使用该武器解决Bi名其它士兵。


    E叔要尽可能地消耗更少耐久度解决很多其它的敌人,求最小消耗与最大杀敌数。

    思路:

    我们把士兵分为两个集合:e1与e2。e1的士兵 Bi = 0 。 e2 的 Bi > 0.

    我们发现。假设能解决e2的随意一个,e2就可以全灭,那么我们对e2依据消耗进行升序排序,消灭e2集合的消耗即为排序后的第一个士兵的Ai。

    其次。要尽可能多地解决e1的士兵,则相同对e1依据消耗进行升序排序,杀到耐久度小于下一士兵Ai为止;

    乍一看,最优解就是先全灭e2再用剩下的耐久度消灭e1较小Ai的敌人,用e2剩下的Bi消耗e1较大Ai的敌人;
    假设不能全灭e2,则用全部耐久度去解决e1的敌人。

    这样做的确非常优了。但还不是最优。考虑这组例子:
    1
    4 5
    2 1
    3 1
    5 0
    100 0
    依照刚才的贪心策略,先解决Bi > 0 的前两个士兵(用袖剑杀死士兵1,用士兵1的武器杀死士兵2),消耗2耐久度。然后用士兵2的武器解决Ai最大的士兵4。士兵3由于耐久度不够则无法解决,答案是3 2。
    可是我们能够先用袖剑杀死士兵1与士兵2。用这两个士兵的武器去解决士兵3,4,明显最优解为4 5。

    于是我们对之前贪心策略做出改进:
    设用袖剑杀死一个 Bi = 0 的士兵1消耗为a。设用士兵武器杀死一个在 Bi > 0 的集合里的士兵2。士兵2的最小消耗为b;
    假设a < b,则用袖剑解决士兵1,用士兵武器解决士兵2;
    否则。则用袖剑解决士兵2。保留士兵武器解决更大消耗的士兵(可能是士兵1)。
    换而言之。就是E叔面对一个 Bi > 0 的士兵,他说:本来准备用士兵武器杀死你。如今我又不想了,我要用袖剑杀死你,由于你的消耗并不大,我要换回用以杀死你的士兵武器。去杀死消耗更大的敌人。

    可能叙述还是有点不清。

    。这个贪心策略看起来极其像dp,然而它真心不是dp。

    。以后思路更清晰的时候再改改吧~

    代码:

    /*
    * @author FreeWifi_novicer
    * language : C++/C
    */
    #include<cstdio>
    #include<iostream>
    #include<cstring>
    #include<cstdlib>
    #include<cmath>
    #include<algorithm>
    #include<string>
    #include<map>
    #include<set>
    #include<vector>
    #include<queue>
    
    using namespace std;
    
    #define clr( x , y ) memset(x,y,sizeof(x))
    #define cls( x ) memset(x,0,sizeof(x))
    #define mp make_pair
    #define pb push_back
    typedef long long lint;
    typedef long long ll;
    typedef long long LL;
    
    /*Nothing is true , everything is permitted*/
    
    const int maxn = 1e5 + 100 ;
    lint n , m ;
    lint kill_e1 , cost1 ;
    lint ans_cost , ans_kill ;
    lint e1[maxn] ;
    
    struct em{
        lint cos , kil ;
    }e2[maxn] ;
    
    bool cmp( em a , em b ){
        return a.cos < b.cos ;
    }
    
    void only_kill_e1( int len1 ){
        lint dur = m ;
        cost1 = 0 ;
        kill_e1 = 0 ;
        int k = 0 ;
        while( k < len1 && dur >= e1[k] ){
            cost1 += e1[k] ;
            kill_e1 ++ ;
            dur -= e1[k++] ;
        }
    }
    
    bool kill_all_e2( int len2 , int len1 ){
        if( !len2 )
            return false ;
        lint dur = m ;
        if( e2[0].cos > dur )
            return false ;
        dur -= e2[0].cos ;
        lint sumb = 0 ;
        for( int i = 0 ; i < len2 ; i++ )
            sumb += e2[i].kil ;
        lint rest = sumb - len2 + 1 ;
        if( rest >= len1 ){//假设多余的sword能够解决掉全部b = 0的敌人,则可解决全部敌人
            ans_cost = e2[0].cos ;
            ans_kill = n ;
            return true ;
        }
        else{
            int i = 0 , j = 1 ; //比較e2[j].cos 与 e1[i]的大小,选择消耗耐久度小的去杀
            lint tmp = len1 - rest ;
            ans_cost = e2[0].cos ;
            ans_kill = len2 + rest ;
            while( i < tmp ){
                if( dur < e1[i] && dur < e2[j].cos ) break ;
                if( j < len2 && e2[j].cos <= e1[i] ){
                    ans_cost += e2[j].cos ;
                    dur -= e2[j].cos ;
                    tmp-- ; j++ ;
                }
                else{
                    ans_cost += e1[i] ;
                    dur -= e1[i] ;
                    i++ ;
                }
                ans_kill ++ ;
            }
            return true ;
        }
    }
    int main(){
    //  freopen("input.txt","r",stdin);
        int t ; cin >> t ; int kase = 1 ;
        while( t-- ){
            cin >> n >> m ;
            ans_kill = kill_e1 = 0 ;
            ans_cost = cost1 = 0 ;
            lint len1 = 0 , len2 = 0 ;
            for( int i = 1 ; i <= n ; i++ ){
                lint a , b ;
                scanf( "%I64d%I64d" , &a , &b ) ;
                if( !b ){
                    e1[len1++] = a ;
                }
                else{
                    e2[len2].cos = a ;
                    e2[len2++].kil = b ;
                }
            }
            printf( "Case %d: " , kase++ ) ;
            sort( e1 , e1 + len1 ) ;
            sort( e2 , e2 + len2 , cmp ) ;
    
            only_kill_e1( len1 ) ;
    
            if( !kill_all_e2( len2 , len1 ) ){
                printf( "%I64d %I64d
    " , kill_e1 , cost1 ) ;
                continue ;
            }
            if( ans_kill > kill_e1 ){
                printf( "%I64d %I64d
    " , ans_kill , ans_cost ) ;
            }
            else{
                if( ans_kill == kill_e1 )
                    printf( "%I64d %I64d
    " , ans_kill , min( ans_cost , cost1 ) ) ;
                else
                    printf( "%I64d %I64d
    " , kill_e1 , cost1 ) ;
            }  
        }
        return 0;
    }
    
  • 相关阅读:
    计算机网络中协议相关的问题(转)
    Vs2013打开项目时,一直处理等待状态,并显示“Microsoft Visual Studio正忙”的提示窗,处理方法(转)
    ASP.NET Core 2.2 十九. Action参数的映射与模型绑定(转)
    ASP.NET Core 2.2 十八.各种Filter的内部处理机制及执行顺序(转)
    ASP.NET Core 2.2 : 十七.Action的执行(Endpoint.RequestDelegate后面的故事)(转)
    ASP.NET Core 2.2 : 十六.扒一扒新的Endpoint路由方案(转)
    【Leetcode】771. Jewels and Stones
    【Leetcode】50. Pow(x, n)
    【Leetcode】 328. Odd Even Linked List
    【leetcode】59.Spiral Matrix II
  • 原文地址:https://www.cnblogs.com/brucemengbm/p/7074278.html
Copyright © 2020-2023  润新知