傳送門做的好累的一道dp= =為了簡化問題,我們對遊戲規則進行了簡化和改編:
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
我們可以將該問題轉化為一道混合揹包,因為每一橫座標下降只有一次,所以看作01揹包中的一件物品,然後每一橫座標可以上公升的次數沒有限制,所以看作完全揹包中的一件物品,然後跑混合揹包就可以了
需要注意的細節:
判斷是否是管子,一定不要用下界,因為管子的下界也可以是地面
判斷撞頂與撞地,撞頂只是不上公升,但不會死,撞地會死
橫座標是以0開始的,而不是1
在乙個橫座標處可以跳無數次,但下降只有那一種高度
交的時候一定要刪注釋
1 #include2 #include3 #include4view codeusing
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()
我可能是在面向資料程式設計:
首先,先打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 ...