動態規劃之DP中判斷是否到達某一狀態(最短期是什麼)?

codevs1684 垃圾陷阱ios

 時間限制: 1 s
 空間限制: 128000 KB
 題目等級 : 黃金 Gold
 
題目描述  Description

卡門——農夫約翰極其珍視的一條Holsteins奶牛——已經落了到「垃圾井」中。「垃圾井」是農夫們扔垃圾的地方,它的深度爲D (2 <= D <= 100)英尺。flask

卡門想把垃圾堆起來,等到堆得與井一樣高時,她就能逃出井外了。另外,卡門能夠經過吃一些垃圾來維持本身的生命。app

每一個垃圾均可以用來吃或堆放,而且堆放垃圾不用花費卡門的時間。ide

假設卡門預先知道了每一個垃圾扔下的時間t(0<t<=1000),以及每一個垃圾堆放的高度h(1<=h<=25)和吃進該垃圾能維持生命的時間f(1<=f<=30),要求出卡門最先能逃出井外的時間,假設卡門當前體內有足夠持續10小時的能量,若是卡門10小時內沒有進食,卡門就將餓死。spa

輸入描述  Input Description

第一行爲2個整數,D 和 G (1 <= G <= 100),G爲被投入井的垃圾的數量。code

第二到第G+1行每行包括3個整數:T (0 < T <= 1000),表示垃圾被投進井中的時間;F (1 <= F <= 30),表示該垃圾能維持卡門生命的時間;和 H (1 <= H <= 25),該垃圾能墊高的高度。blog

輸出描述  Output Description

若是卡門能夠爬出陷阱,輸出一個整表示最先何時能夠爬出;不然輸出卡門最長能夠存活多長時間。排序

樣例輸入  Sample Input

20 4ip

5 4 9內存

9 3 2

12 6 10

13 1 1

樣例輸出  Sample Output

13

數據範圍及提示  Data Size & Hint

[樣例說明]

卡門堆放她收到的第一個垃圾:height=9;

卡門吃掉她收到的第二個垃圾,使她的生命從10小時延伸到13小時;

卡門堆放第3個垃圾,height=19;

卡門堆放第4個垃圾,height=20。

 

#include<iostream>
using namespace std;
#include<algorithm>
#include<cstdio>
#include<cstring>
int D,G;
#define N 101
struct Lj{
  int t,f,h;
};
Lj lj[N];
int max(int a,int b)
{
    if(a>b) return a;
    return b;
}
int cmp(Lj a, Lj b)
{
   return a.t<b.t;
}
int maxh[N],dp[N][N];
//f[i][j]表示投入第i個垃圾後高度爲j的最大剩餘生命值,其中T=i表示可使用i時刻以前的一切垃圾
//①把這個垃圾摞起來:用f[i-1]中的每一個狀態去更新:f[i-1][j]-(兩個垃圾的時間差)->f[i][j+這個垃圾的高度]
//②壯士乾了這碗熱翔:用f[i-1]中的每一個狀態去更新:f[i-1][j]+(這個垃圾的時間)->f[i][j]
//每次轉移O(D),共轉移G次
//maxh表示到了第i個垃圾所能達到的最大高度
void input()
{
    scanf("%d%d",&D,&G);
    
    for(int i=1;i<=G;++i)
        scanf("%d%d%d",&lj[i].t,&lj[i].f,&lj[i].h);
    sort(lj+1,lj+G+1,cmp);//先把垃圾按照時間順序排序
}
void DP()
{
    
    memset(dp,-1,sizeof(dp));
    dp[0][0]=10;
    lj[0].t=0;
        maxh[0]=0;
    int i,j;
    for(i=1;i<=G;++i)
    {
        bool sur=false;//是否死亡標誌
        int nowh=lj[i].h;
        int nowf=lj[i].f;
        int dt=lj[i].t-lj[i-1].t;//時間差
        for(j=0;j<=maxh[i-1];++j)//循環到前一個點所能到達的最大高度
        {
            if(dp[i-1][j]-dt>=0)/*把垃圾堆起來,轉移方程始終取生命的最大值,*/
            {
                dp[i][j+nowh]=max(dp[i][j+nowh],dp[i-1][j]-dt);
                sur=true;
                maxh[i]=max(maxh[i],j+nowh);
            }

        }
        for(j=0;j<=maxh[i-1];++j)
        {
            if(dp[i-1][j]-dt>=0)/*把垃圾吃掉*/
            {
                dp[i][j]=max(dp[i][j],dp[i-1][j]-dt+nowf);
                sur=true;
                maxh[i]=max(maxh[i],j);
            }
        }
        if(!sur)//死亡
            break;
        if(maxh[i]>=D)//出坑
        {
            printf("%d\n",lj[i].t);
            return ;    
        }
    }

    int sum=0;
    for(j=1;j<i;++j)
    sum+=lj[j].f;//最長生命,注意第i個垃圾沒吃
    printf("%d\n",sum+10);
}
int main()
{
    input();
    DP();
    getchar();
    return 0; 
}
View Code

 2.lojs [NOIP2007] 守望者的逃離

★☆   輸入文件:escape.in   輸出文件:escape.out   簡單對比
時間限制:1 s   內存限制:128 MB

守望者的逃離

【問題描述】

惡魔獵手尤迪安野心勃勃.他背叛了暗夜精靈,率深藏在海底的那加企圖叛變:守望者在與尤迪安的交鋒中遭遇了圍殺.被困在一個荒蕪的大島上。爲了殺死守望者,尤迪安開始對這個荒島施咒,這座島很快就會沉下去,到那時,島上的全部人都會遇難:守望者的跑步速度,爲17m/s, 以這樣的速度是沒法逃離荒島的。慶幸的是守望者擁有閃爍法術,可在1s內移動60m,不過每次使用閃爍法術都會消耗魔法值10點。守望者的魔法值恢復的速度爲4點/s,只有處在原地休息狀態時才能恢復。

如今已知守望者的魔法初值M,他所在的初始位置與島的出口之間的距離S,島沉沒的時間T。你的任務是寫一個程序幫助守望者計算如何在最短的時間內逃離荒島,若不能逃出,則輸出守望者在剩下的時間內能走的最遠距離。注意:守望者跑步、閃爍或休息活動均以秒(s)爲單位。且每次活動的持續時間爲整數秒。距離的單位爲米(m)。

【輸入】

輸入文件escape.in僅一行,包括空格隔開的三個非負整數M,S,T。

【輸出】

輸出文件escape.out包含兩行:

第1行爲字符串"Yes"或"No" (區分大小寫),即守望者是否能逃離荒島。

第2行包含一個整數,第一行爲"Yes" (區分大小寫)時表示守望着逃離荒島的最短期

第一行爲"No" (區分大小寫) 時表示守望者能走的最遠距離。

【輸入輸出樣例1】

escape.in

39 200 4

 

escape.out

No

197

【輸入輸出樣例2】

escape.in

36 255 10

 

escape.out

Yes

6

【限制】

30%的數據知足: 1 <= T<= 10, 1 <=S<= 100

50%的數據知足: 1 <= T <= 1000, 1 <= S <= 10000

100%的數據知足: 1 <= T <= 300000, 0 <= M<=1000 1 <=S <= 10^8

用單純的貪心作,
貪心策略:(注意,順序不能反!)

   1: 若是有魔法,先放法。

2:若是剩下的距離>=120,就等5s,閃兩次。共耗時7S,前進了120米,比跑7s走的遠(7×17=119)即,用去的時間tt=tt+7;行走的距離爲ss:ss=ss+120;當tt=t-7時,ss<s時,m>=2時,應當放棄採用此策略。(由於此時,咱們能夠等的1秒或是2秒就能夠閃了。)若是t-tt<7,放棄此策略。

    3:若是 (s-ss>=34) and (m>=6) and (t-tt>=2),那麼就選擇閃爍,等一秒,閃一秒。魔法減6。

    4:若是   (s-ss>=51) and (m>=2 ) and (t-tt>=3) ,那麼就選擇閃爍,等兩秒,閃一秒,魔法減2。

    5:若是以上的到的結果的都不能跑出來,那麼就選擇跑路吧。最後判斷可否跑出。

/*顯而易見的貪心策略:就是分類比較麻煩*/
#include<iostream>
using namespace std;
#include<cstdio>
int m,s,t;
int s1,t1;
int main()
{
   scanf("%d%d%d",&m,&s,&t);
   s1=0;t1=0;
   while(m>=10&&t-t1>0&&s-s1>0)/*先把能用的魔法用完*/
   {
       if(s-s1>17)
       {
           m-=10;
           s1+=60;
           t1++;
       }
       else {
           printf("Yes\n%d\n",t-t1-1);/*用完魔法的過程當中判斷是否跑出*/
           return 0;
       }
   }
   while(s-s1>0&&t-t1>0)/*四種逃跑狀況*/
   {
       if(m<2&&m>=0&&t-t1>=7&&s-s1>119)
       {
           s1+=60*2;
           t1+=7;
       }
       else if(m>=2&&m<=5&&t-t1>=3&&s-s1>17*3)
       {
           t1+=3;
           m-=2;
           s1+=60;
       }
       else if(m>=6&&t-t1>=2&&s-s1>17*2)
       {
           t1+=2;
           s1+=60;                 
           m-=6;
       }
       else 
       {
           s1+=17;
           t1++;
       }
   }
   if(s1>=s) printf("Yes\n%d\n",t1);/*最後判斷是否跑出*/
   else printf("No\n%d\n",s1);
   return 0;
}
View Code
相關文章
相關標籤/搜索