noip2014 飛揚的小鳥


P1941 飛揚的小鳥

    • 467通過
    • 2.5K提交
  • 題目提供者該用戶不存在
  • 標簽動態規划2014NOIp提高組
  • 難度提高+/省選-

提交該題 討論 題解 記錄

最新討論

題目描述

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

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

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

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

  3. 小鳥每個單位時間沿橫坐標方向右移的距離為1 ,豎直移動的距離由玩家控制。如果點擊屏幕,小鳥就會上升一定高度X ,每個單位時間可以點擊多次,效果疊加;

如果不點擊屏幕,小鳥就會下降一定高度Y 。小鳥位於橫坐標方向不同位置時,上升的高度X 和下降的高度Y 可能互不相同。

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

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

輸入輸出格式

輸入格式:

 

輸入文件名為 bird.in 。

第1 行有3 個整數n ,m ,k ,分別表示游戲界面的長度,高度和水管的數量,每兩個

整數之間用一個空格隔開;

接下來的n 行,每行2 個用一個空格隔開的整數X 和Y ,依次表示在橫坐標位置0 ~n- 1

上玩家點擊屏幕后,小鳥在下一位置上升的高度X ,以及在這個位置上玩家不點擊屏幕時,

小鳥在下一位置下降的高度Y 。

接下來k 行,每行3 個整數P ,L ,H ,每兩個整數之間用一個空格隔開。每行表示一

個管道,其中P 表示管道的橫坐標,L 表示此管道縫隙的下邊沿高度為L ,H 表示管道縫隙

上邊沿的高度(輸入數據保證P 各不相同,但不保證按照大小順序給出)。

 

輸出格式:

 

輸出文件名為bird.out 。

共兩行。

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

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

 

輸入輸出樣例

輸入樣例#1:
10 10 6 
3 9  
9 9  
1 2  
1 3  
1 2  
1 1  
2 1  
2 1  
1 6  
2 2  
1 2 7 
5 1 5 
6 3 5 
7 5 8 
8 7 9 
9 1 3 
輸出樣例#1:
1
6

輸入樣例#2:
10 10 4 
1 2  
3 1  
2 2  
1 8  
1 8  
3 2  
2 1  
2 1  
2 2  
1   2  
1 0 2 
6 7 9 
9 1 4 
3 8 10  
輸出樣例#2:
0
3

說明

【輸入輸出樣例說明】

如下圖所示,藍色直線表示小鳥的飛行軌跡,紅色直線表示管道。

【數據范圍】

對於30% 的數據:5 ≤ n ≤ 10,5 ≤ m ≤ 10,k = 0 ,保證存在一組最優解使得同一單位時間最多點擊屏幕3 次;

對於50% 的數據:5 ≤ n ≤ 2 0 ,5 ≤ m ≤ 10,保證存在一組最優解使得同一單位時間最多點擊屏幕3 次;

對於70% 的數據:5 ≤ n ≤ 1000,5 ≤ m ≤ 1 0 0 ;

對於100%的數據:5 ≤ n ≤ 100 0 0 ,5 ≤ m ≤ 1 0 00,0 ≤ k < n ,0<X < m ,0<Y <m,0<P <n,0 ≤ L < H ≤ m ,L +1< H 。

分析:每次可以跳xi,可以跳k次,每次只能往上跳和往下掉一次,這難道是背包?而且還不是簡單的背包,完全背包+0-1背包?對.首先可以明確向上是完全背包,向下是0-1背包,但是不能同時向上和向下,必須要分開處理,可以參考守望者的逃離,具體為什么,是因為會造成決策混亂,因為f[i][j]可以從f[i][j-x[i]]得到,而f[i][j-x[i]]可能是由下落得到的,不能夠不點又點.那么先遞推向上的,首先f[i][j]可以從f[i-1][j-x[i]]得到,然后又可以通過f[i][j-x[i]]得到,那么遞推取最小值即可,不過注意到跳到m游戲不會結束,所以要從m-x[i]到m要繼續枚舉j來更新f[i][m],然后依據這個來更新向下的,柱子所覆蓋的全部賦值為inf,最后判斷一下就可以出答案了.

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>

using namespace std;

const int maxn = 10010;
const int inf = 1000000000;

int n, m, k, p, ans,up[maxn],down[maxn],x[maxn],y[maxn],f[maxn][1010];

int main()
{
    scanf("%d%d%d", &n, &m, &k);
    up[n] = m + 1;
    down[n] = 0;
    for (int i = 0; i < n; i++)
    {
        scanf("%d%d", &x[i], &y[i]);
        up[i] = m + 1;
        down[i] = 0;
    }
    for (int i = 1; i <= k; i++)
    {
        scanf("%d", &p);
        scanf("%d%d", &down[p], &up[p]);
    }
    for (int i = 1; i <= n; i++)
        for (int j = 0; j <= m; j++)
            f[i][j] = inf;
    f[0][0] = inf;
    for (int i = 1; i <= n; i++)
    {
        for (int j = x[i - 1];j <= m; j++)
        {
            f[i][j] = min(f[i][j], f[i - 1][j - x[i - 1]] + 1);
            f[i][j] = min(f[i][j], f[i][j - x[i - 1]] + 1);
        }
        for (int j = m - x[i - 1]; j <= m; j++)
        {
            f[i][m] = min(f[i][m], f[i - 1][j] + 1);
            f[i][m] = min(f[i][m], f[i][j] + 1);
        }
        for (int j = down[i] + 1; j <= up[i] - 1; j++)
            if (j + y[i - 1] <= m)
                f[i][j] = min(f[i][j], f[i - 1][j + y[i - 1]]);
        for (int j = 1; j <= down[i]; j++)
            f[i][j] = inf;
        for (int j = up[i]; j <= m; j++)
            f[i][j] = inf;
    }
    ans = inf;
    int cnt = k;
    for (int i = n; i >= 1; i--){
        for (int j = down[i] + 1; j <= up[i] - 1; j++)
            ans = min(ans, f[i][j]);
            if (ans != inf)
                break;
                if (up[i] != m + 1)
                cnt--;
        }
    if (cnt == k)
        printf("1\n%d\n", ans);
    else
        printf("0\n%d\n", cnt);

    return 0;
}

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM