1. 程式人生 > >2017百度之星資格賽—1003度度熊與邪惡大魔王

2017百度之星資格賽—1003度度熊與邪惡大魔王

                       度度熊與邪惡大魔王

題目傳送門
Accepts: 3608 Submissions: 22145
Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)
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
其他題目就不發部落格了(有些也沒做出來!!),感覺這次百度之星資格賽題目資料有毒,吐槽,其他題目也不好說,感覺這個題目正常點。
這個題目我當時想到的就是動態規劃,但是評論中很多人說是貪心,我一直不理解,認為他們對於貪心和動態規劃之間的範疇沒有搞清楚(可能是我沒搞清楚!有錯誤請dalao指正),可能有dalao能貪心出來(一臉敬佩);雖然知道是動態規劃問題,可轉移方程怎麼搞?我一直在想(比較弱!!),想了許多的動態規劃的方法,還是用打表的方式(就是每種可能出現的怪獸,根據這組資料的技能和傷害值,用陣列記錄它消耗的最小晶石數目),這樣全部出來了就方便了,將出現的怪獸消耗的最小晶石數目加起來即可;比賽開始一個小時才AC這個題目,一發AC(比較開心),有dalao有更好的方法請賜教(萬分感謝!!)。
AC程式碼:

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const long long INF=1e15;
const int maxn=100000+10;
const int maxm=1000+10;
struct P{
    int live;//怪獸的生命值 
    int figth;//怪獸的防禦力 
}p[maxn];
struct V{
    int money;//技能的消耗晶石數目
    int shai;//技能的傷害值 
}v[maxm];
long long  ans[maxm][15];//儲存每種怪獸需要消耗的最小晶石數目
int n,m;
bool cmpp(P a,P b)
{
    return a.figth>b.figth;//以怪獸的防禦力從大到小排序 
}
bool cmpv(V a,V b)
{
    return a.shai>b.shai;//以技能的傷害值從大到小排序 
}
int main()
{
     while(scanf("%d%d",&n,&m)==2)
     {
         int i,j,k;
         for(i=0;i<n;i++)
         {
             scanf("%d%d",&p[i].live,&p[i].figth);
        }
        for(i=0;i<m;i++)
        {
            scanf("%d%d",&v[i].money,&v[i].shai);
        }
        sort(p,p+n,cmpp);
        sort(v,v+m,cmpv);
        if(p[0].figth>=v[0].shai)
        //當怪獸的最大防禦力大於等於技能的最大傷害值,不可能消滅全部怪獸 
        {
            printf("-1\n");
            continue;
        }
        else
        {
            fill(&ans[0][0],&ans[0][0]+maxm*15,INF);
            //初始每種怪獸都需要消耗無窮大晶石數目,因為是取最小值 
            for(i=0;i<=10;i++)
            ans[0][i]=0;
            //當怪獸的生命值為0時,消耗0晶石
            for(i=1;i<=1000;i++)
             {
                 for(j=0;j<=10;j++)
                 {
                     for(k=0;k<m;k++)
                     {
                         int s=v[k].shai;
                         if(s>=i+j)
                         s=i;
                         else
                         {
                             if(s<=j)
                             s=0;
                             else
                             s-=j;
                         }
                         //因為i-s不能<0,所以進行判斷賦值,i-s相當於怪獸被技能攻擊還剩餘的生命值  
                         ans[i][j]=min(ans[i][j],ans[i-s][j]+v[k].money);
                     }
                 }
             }
             long long sum=0;
             for(i=0;i<n;i++)
             sum+=ans[p[i].live][p[i].figth];
             //加上每種怪獸需要消耗的最小晶石數目
             printf("%I64d\n",sum);
        }
     }
    return 0;
}