[DP]Luogu 2014NOIP提升組 飛揚的小鳥題解

 

2014NOIP提升組飛揚的小鳥題解

題目描述算法

Flappy Bird是一款風靡一時的休閒手機遊戲。玩家須要不斷控制點擊手機屏幕的頻率來調節小鳥的飛行高度,讓小鳥順利經過畫面右方的管道縫隙。若是小鳥一不當心撞到了水管或者掉在地上的話,便宣告失敗。app

爲了簡化問題,咱們對遊戲規則進行了簡化和改編:spa

遊戲界面是一個長爲 n,高爲 m 的二維平面,其中有 k 個管道(忽略管道的寬度)。code

小鳥始終在遊戲界面內移動。小鳥從遊戲界面最左邊任意整數高度位置出發,到達遊戲界面最右邊時,遊戲完成。blog

小鳥每一個單位時間沿橫座標方向右移的距離爲 1,豎直移動的距離由玩家控制。若是點擊屏幕,小鳥就會上升必定高度 X,每一個單位時間能夠點擊屢次,效果疊加;若是不點擊屏幕,小鳥就會降低必定高度 Y。小鳥位於橫座標方向不一樣位置時,上升的高度 X 和降低的高度 Y 可能互不相同。遊戲

小鳥高度等於 0 或者小鳥碰到管道時,遊戲失敗。小鳥高度爲 m 時,沒法再上升。get

如今,請你判斷是否能夠完成遊戲。若是能夠,輸出最少點擊屏幕數;不然,輸出小鳥最多能夠經過多少個管道縫隙。string

輸入格式it

 11 行有 33 個整數 n,m,k,分別表示遊戲界面的長度,高度和水管的數量,每兩個整數之間用一個空格隔開;io

接下來的 n 行,每行 2 個用一個空格隔開的整數 X  Y,依次表示在橫座標位置 0n上玩家點擊屏幕後,小鳥在下一位置上升的高度 X,以及在這個位置上玩家不點擊屏幕時,小鳥在下一位置降低的高度 Y

接下來 k 行,每行 3 個整數 P,L,H,每兩個整數之間用一個空格隔開。每行表示一個管道,其中 P 表示管道的橫座標,表示此管道縫隙的下邊沿高度,表示管道縫隙上邊沿的高度(輸入數據保證 P 各不相同,但不保證按照大小順序給出)。

輸出格式

共兩行。

第一行,包含一個整數,若是能夠成功完成遊戲,則輸出 1,不然輸出 0

第二行,包含一個整數,若是第一行爲 1,則輸出成功完成遊戲須要最少點擊屏幕數,不然,輸出小鳥最多能夠經過多少個管道縫隙。

數據範圍

n<=10000,m<=1000

題目分析

^-^

首先讀題:(重點)

每一個單位時間能夠點擊屢次,效果疊加

——有多種狀況,這是一個徹底揹包

若是不點擊屏幕,小鳥就會降低必定高度

——只有一種狀況,這是一個01揹包

小鳥高度爲 m 時,沒法再上升

——須要特判

分析:

f[i][j]表示跳到當前位置的最少次數

rise[i]表示點一下上升的高度

fall[i]表示不點降低的高度

 

首先畫一張圖,

 

咱們能夠發現

f[i][j]的位置可能從

f[i-1][j+fall[i-1]]滑下來

或者從f[i-1][j-t*rise[i-1]]跳過來

(1<=j-t*rise[i-1]<=m)

 

f[i-1][j+1]滑下來很好解決,01揹包嘛

代碼以下

 

        for(j=1;j<=m-fall[i-1];j++)
            f[i][j]=min(f[i][j],f[i-1][j+fall[i-1]]);

 

可是從f[i-1][j-t*rise[i-1]]跳過來就很差辦了

若是每次都直接枚舉全部j-t*rise[i-1]的話,

根據題目數據範圍可推出(n<=10000,m<=1000)

最壞有超過50億次運算

確定會超時#-_-

可是畢竟這是一個徹底揹包啊

有沒有其餘方法呢

咱們能夠用徹底揹包的思路

j從小到大增長

每次將f[i][j-rise[i-1]]f[i-1][j-rise[i-1]]的狀態轉移過來

由於j是從小到大的,

因此f[i][j-rise[i-1]]實際上是轉移的

f[i-1][j-rise[i-1]*t]f[i-1][j-rise[i-1]*2]的狀態

無論它轉移的是那個位置過來的

f[i][j-rise[i-1]]已經是當前位置的最優

這樣就能夠實如今同一時間點裏屢次點擊屏幕

 

代碼以下

 

        for(j=rise[i-1]+1;j<=rise[i-1]+m;j++)
            f[i][j]=min(f[i-1][j-rise[i-1]]+1,f[i][j-rise[i-1]]+1);

 

算法的正確性

因而我就滿心歡喜地交了上去^-^

 

        for(j=1;j<=m-fall[i-1];j++)
            f[i][j]=min(f[i][j],f[i-1][j+fall[i-1]]);
        for(j=rise[i-1]+1;j<=rise[i-1]+m;j++)
            f[i][j]=min(f[i-1][j-rise[i-1]]+1,f[i][j-rise[i-1]]+1);

 

(o)

 

第18點是來幹什麼的

什麼,竟(dang)WA

首先,

管道沒有特殊處理,

在處理完當前狀態後

要將管道位置的數值賦值爲極大值

其次,

向上跳躍的處理要在向下滑落的處理以前

由於同一時間單位內

在滑落以後不能繼續跳躍

第三,

到達屏幕頂端的位置要特殊處理

最後,

f[i][0]要賦值爲0

由於開始小鳥能夠在任何位置

 

終於......

 

 

AC代碼

 

#include<cstdio>
#include<cstring>
#include<algorithm>
#define infi 0x7fffffff
#define N 10000
#define M 1000
using namespace std;
int n,m,k;
int rise[N+2],fall[N+2];
int f[N+2][M*2+2];
int l[N+2],h[N+2];
bool a[N+2];//a[i]表示橫座標爲i的位置是否有管道
template<typename T>inline void r(T& x){
    char temp=getchar();bool u=0;
    for(x=0;temp<'0'||temp>'9';u=temp=='-',temp=getchar());
    for(;temp>='0'&&temp<='9';x=x*10+temp-'0',temp=getchar());
    if(u)x=-x;
    return ;
}//快讀
int main(){
    register int i,j,ans=infi;
    memset(f,127,sizeof f);
    memset(a,0,sizeof a);
    r(n),r(m),r(k);
    for(i=1;i<=n;i++)
        l[i]=0,h[i]=m+1;
    {
        register int p;
        for(i=0;i<n;i++)r(rise[i]),r(fall[i]);
        for(i=1;i<=k;i++)
            r(p),r(l[p]),r(h[p]),a[p]=1;
    }
    for(i=1;i<=m;i++)
        f[0][i]=0;
    for(i=1;i<=n;i++){
        for(j=rise[i-1]+1;j<=rise[i-1]+m;j++)//跳躍
            f[i][j]=min(f[i-1][j-rise[i-1]]+1,f[i][j-rise[i-1]]+1);
//j<=rise[i-1]+m:再往上跳沒有意義
        for(j=m+1;j<=rise[i-1]+m;j++)     //頂端特殊處理
            f[i][m]=min(f[i][m],f[i][j]);
        for(j=1;j<=m-fall[i-1];j++)         //下滑
            f[i][j]=min(f[i][j],f[i-1][j+fall[i-1]]);
        for(j=1;j<=l[i];j++)               //管道賦值爲極大值
            f[i][j]=2e9;
        for(j=h[i];j<=m;j++)
            f[i][j]=2e9;
    }
    for(i=1;i<=m;i++)ans=min(ans,f[n][i]);
    if(ans<2e9)printf("1\n%d\n",ans);
    else{
        register int flag=0;
        for(i=n-1;i>=1&&!flag;i--)
            for(j=1;j<=m&&!flag;j++)
                if(f[i][j]<2e9){
                    flag=0;
                    flag=i;
                }
        ans=0;
        for(i=1;i<=flag;i++)
            if(a[i])ans++;
        printf("0\n%d\n",ans);
    }
    return 0;
}
//碼醜勿噴^-^
相關文章
相關標籤/搜索