NOIP2014 飛揚的小鳥

2022-03-27 10:33:04 字數 3396 閱讀 6966

傳送門

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

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

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

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

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

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

輸入檔名為 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,則輸出成功完成遊戲需要最少點選螢幕數,否則,輸出小鳥最多可以通過多少個管道縫隙。

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 6

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 100 3

對於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

做的好累的一道dp= =

我們可以將該問題轉化為一道混合揹包,因為每一橫座標下降只有一次,所以看作01揹包中的一件物品,然後每一橫座標可以上公升的次數沒有限制,所以看作完全揹包中的一件物品,然後跑混合揹包就可以了

需要注意的細節:

判斷是否是管子,一定不要用下界,因為管子的下界也可以是地面

判斷撞頂與撞地,撞頂只是不上公升,但不會死,撞地會死

橫座標是以0開始的,而不是1

在乙個橫座標處可以跳無數次,但下降只有那一種高度

交的時候一定要刪注釋

1 #include2 #include3 #include4

using

namespace

std;

5 inline int

read()

12int

n,m,k;

13int x[10005],y[10005

];14

int ans(0x7fffffff

);15 inline void dfs(int h,int cnt,int

an)20

if(h-y[cnt]>0

)21 dfs(h-y[cnt],cnt+1

,an);

22 dfs(min(h+x[cnt],m),cnt+1,an+1

);23

}24 inline void

work()

28int f[10005][1005

];29

int lim_d[10005],lim_u[10005

];30

intinf;

31 inline int

gg()

41if(k==0

)45 memset(f,0x3f,sizeof

(f));

46//

memset(f[0],0,sizeof(f[0]));

47 f[0][0]=inf=f[1][1

];48

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

49 f[0][i]=0;50

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

55for(int j=m-x[i-1];j<=m;++j)

59for(int j=lim_d[i]+1;jj)

60if(j+y[i-1]<=m)

61 f[i][j]=min(f[i][j],f[i-1][j+y[i-1

]]);

62for(int j=1;j<=lim_d[i];++j)

63 f[i][j]=inf;

64for(int j=lim_u[i];j<=m;++j)

65 f[i][j]=inf;66}

67int

cs(k),ans(inf);

68for(int i=n;i>0;--i)

76if(cs==k)

77 printf("

1\n%d

",ans);

78else

79 printf("

0\n%d

",cs);80}

81int

k(gg());

82int main()

view code

我可能是在面向資料程式設計:

首先,先打30分k=0演算法,先想了想怎麼推,然後只拿了十分= =,然後就開始特判, if(k==0) dfs(); 

然後就開始打$o(nm^)$的dp,竟然只有55分,一看,我tm判管子是按下界是否為零判的,然後管子下界可以為零= =

最後才開始打揹包

我。。。

NOIP2014 飛揚的小鳥

題目 分析 乙個揹包問題。i,j 是跳上來的情況時 可以由 i,j k 得到,則問題得到解決。注意 f陣列要先進行上公升操作,再進行下降操作,否則 i,j k 有可能是下降得到的,從而得到錯解 吸取我的教訓吧,調了好長時間 include include using namespace std co...

NOIP2014飛揚的小鳥

天哪細節問題調了乙個鐘,手速不夠快思路不夠清晰寫了乙個鐘,感覺一道第三題就要花掉我2個鐘那我比賽的時候腫麼辦qaq 說下這道題,首先純暴力,70分到手,然後我們把01揹包的轉移變成有上界的完全揹包,還有一些特殊情況特殊轉移,還是比較好看的,去年比賽不知是電腦問題還是什麼一直沒輸出,蠢到家了然後這題爆...

NOIP2014 飛揚的小鳥

令f i j 表示飛翔到 i,j 的最小點選次數 f i j min f i 1 j k x i 1 k,f i 1 j y i 1 這樣做複雜度o n 2m 考慮優化這個過程,先考慮上公升的情況,則f i j 有兩類決策轉移 1.f i j f i 1 j x i 1 2.f i j min f ...