飛揚的小鳥

2022-02-26 14:22:18 字數 2937 閱讀 5546

【題目描述】

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

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

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

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

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

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

【輸入描述】

第一行輸入三個整數n、m、k,分別表示遊戲介面的長度、高度和水管的數量;

接下來n行,每行輸入兩個整數x和y,表示在橫座標位置0~n-1上點選螢幕後,小鳥在下一位置上公升的高度x,以及在這個位置上玩家不點選螢幕時,小鳥在下一位置下降的高度y;

接下來k行,每行輸入三個整數p、l、h,其中p表示管道的橫座標,l表示此管道縫隙的下邊沿高度為l,h表示管道縫隙上邊沿的高度(輸入資料保證p各不相同,但不保證按照大小順序給出)。

【輸出描述】

第一行,如果可以成功完成遊戲,輸出1,否則輸出0;

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

【樣例輸入】

樣例1:

10 10 6

3 96 9

1 21 3

1 21 1

2 12 1

1 62 2

1 2 7

5 1 5

6 3 5

7 5 8

8 7 9

9 1 3

樣例2:

10 10 4

1 23 1

2 21 8

1 83 2

2 12 1

2 21 2

1 0 2

6 7 9

9 1 4

3 8 10

【樣例輸出】

樣例1:16

樣例2:03

【資料範圍及提示】

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

對於50%的資料:5 ≤ n ≤ 20,5 ≤ m ≤ 10,保證存在一組最優解使得同一單位時間最多點選螢幕3次;

對於70%的資料:5 ≤ n ≤ 1000,5 ≤ m ≤ 100;

對於100%的資料:5 ≤ n ≤ 10000,5 ≤ m ≤ 1000,0 ≤ k < n,0 < x < m,0 < y < m,0 < p < n,0 ≤ l < h ≤ m,l+1 < h。

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

源**:

#include

#include

#define inf 1000000000

using

namespace

std;

int f[10001][1001]=;

int x[10001],y[10001],up[10001],down[10001

];int

n,m,k;

int main() //

一壺濁酒盡餘歡,今宵也腦殘。

for (int a=0;a)

scanf(

"%d%d

",&x[a],&y[a]);

for (int a=0;a)

int num=0; //

儲存已經通過的管道數。

for (int a=1;a<=n;a++)

for (int b=m-x[a-1];b<=m;b++) //

頂上特判。

f[a][m]=min(f[a][m],min(f[a-1][b],f[a][b])+1

);

for (int b=down[a]+1;b//

來自上方,不可能掉多次。

if (b+y[a-1]<=m)

f[a][b]=min(f[a][b],f[a-1][b+y[a-1

]]);

for (int b=1;b<=down[a];b++) //

給障礙物賦最大值。

f[a][b]=inf;

for (int b=up[a];b<=m;b++) //

同理。 f[a][b]=inf;

bool t(0

);

for (int b=1;b<=m;b++) //

判斷是否有可行解。

if (f[a][b]

if (!t)

else

if (up[a]!=m+1) //

判斷是否有管道。

num++;

}int ans=inf;

for (int a=1;a<=m;a++)

ans=min(ans,f[n][a]);

printf(

"1\n%d

",ans);

return0;

}/*類似於棋盤型dp,注意上公升的次數不限。狀態轉移方程為:

f[i][j]=min(f[i-1][j+y[i-1]],f[i-1][j-x[i-1]]+1,f[i][j-x[i-1]]+1)。

其中完全揹包的垂直疊加取優法值得學習借鑑。

*/

飛揚的小鳥

顯然的思路,用網路流做。對每個洞拆點,i.j表示第i個洞被通過這個洞的倒數第j隻鳥通過。然後連邊跑費用流。然而邊數太多直接 怎麼辦?注意到i.j沒被流i.j 1就絕不可能被流。因此動態加邊,初始只連所有到x.1的。目前連到x.y,流成功一次加上所有到x.y 1的邊。然後莫名很慢,所以這裡本辣雞加上了...

飛揚的小鳥

飛揚的小鳥 這一題開始看到時就知道是dp,但作死打了個dfs,只有75分 卡常 好 includeusing namespace std const int n 10005 const int inf 9999999 int g sum n g up n g down n up n down n n...

飛揚的小鳥

首先這道題爆搜可做,理論上可以拿50分的,但由於windows下棧空間只有3w多,所以只能拿到35分。然後我們考慮dp 應該很容易想到是dp 定義狀態f i j 為在點 i,j 時最少的觸屏次數,然後列舉觸屏次數轉移即可。這樣複雜度是o nm 2 可以拿70分,但這裡很容易犯的的乙個錯誤就是當在螢幕...