NOIP2014 D1T3 [洛谷P1941] 飛揚的小鳥

莫名的ans++讓我空白了好久

題目描述

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

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

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

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

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

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

現在,請你判斷是否可以完成遊戲。如果可以,輸出最少點擊屏幕數;否則,輸出小鳥最多可以通過多少個管道縫隙。

輸入輸出格式

輸入格式:

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

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

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

輸出格式:

共兩行。

第一行,包含一個整數,如果可以成功完成遊戲,則輸出 1,否則輸出0。

第二行,包含一個整數,如果第一行爲 1,則輸出成功完成遊戲需要最少點擊屏幕數,否則,輸出小鳥最多可以通過多少個管道縫隙。

 

Solution

看到題幹所給的n,m範圍,想到DP解法

設定f[i][j]爲小鳥在f[i][j]位置的時候最少的點擊數量

DP分兩種:

小鳥向上飛時可以在單位時間內連續點許多次,所以是完全揹包

小鳥向下飛時在每一單位時間內只下降一個Y,是一個01揹包

有不可以飛的區域,考慮在這個區域將f[i][j]設定爲INF

題目中有一個特別說明的點:小鳥的高度達到m時無法再上升

這就需要我們在dp到高度爲m的時候進行特判

輸出:

可以將最後一列的f值都掃一遍來判斷

如果可以通過那麼直接輸出

不能通過的話就從後往前找可以通過的位置

對於每一列只能有一個管道,在有管道的列上打個標記,統計標記數目

Code:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
int n,m,k;
int x[10001],y[10001];
int f[10001][2010];
int a,b,c;
int low[10001],high[10001];
bool check[10001];
int ans;
int main()
{
    scanf("%d%d%d",&n,&m,&k);
    for(int i=1;i<=n;i++)
    scanf("%d%d",&x[i],&y[i]);
    for(int i=1;i<=n;i++)
    {
        low[i] = 1;
        high[i] = m;    
    }
    for(int i=1;i<=k;i++)
    {
        scanf("%d%d%d",&a,&b,&c);
        check[a] = 1;
        low[a] = b + 1;
        high[a] = c - 1;
    }
    memset(f,0x3f3f3f,sizeof(f));
    for(int i=1;i<=m;i++)
    f[0][i] = 0;
    for(int i=1;i<=n;i++)
    {
        for(int j=x[i]+1;j<=x[i]+m;j++)
        f[i][j]=min(f[i-1][j-x[i]]+1,f[i][j-x[i]]+1);
        for(int j=m+1;j<=x[i]+m;j++)
        f[i][m]=min(f[i][m],f[i][j]);
        for(int j=1;j<=m-y[i];j++)
        f[i][j]=min(f[i][j],f[i-1][j+y[i]]);
        for(int j=1;j<low[i];j++)
        f[i][j]=0x3f3f3f;
        for(int j=high[i]+1;j<=m;j++)
        f[i][j]=0x3f3f3f;
    }
    ans = 0x3f3f3f;
    for(int i=1;i<=m;i++)
    {
        ans = min(ans,f[n][i]);
    }
    if(ans < 0x3f3f3f)
    {
        printf("1\n%d",ans);
    }
    else
    {
        int i,j;
        for(i=n;i>=1;i--)
        {
            for(j=1;j<=m;j++)
            if(f[i][j] < 0x3f3f3f)
            break;
            if(j <= m)
            break;    
        }
        ans = 0;
        for(int k=1;k<=i;k++)
        {
            if(check[k])
            ans++;
        }
        printf("0\n%d",ans);
        return 0;
    }
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章