標籤:
問題 K: 【動態規劃】攔截飛彈時間限制: 1 Sec 記憶體限制: 256 MB
提交: 39 解決: 10
[提交][狀態][討論版]題目描述張琪曼:“老師,修羅場是什嗎?”
墨老師:“修羅是佛家用語,修羅畢生以戰鬥為目標,修羅場指的是他們之間的死鬥坑,人們通常用‘修羅場’來形容慘烈的戰場。後來又引申出‘一個人在困境中做絕死奮鬥’的意思。所以,這其實也在暗示我們,即使是身處絕境,也不要放棄奮鬥。再說了,情況其實沒有這麼糟糕,因為我們最新的飛彈攔截系統已經研製好了。”
魔法世界為了防禦修羅王軍團的飛彈襲擊,開發出一種飛彈攔截系統──“要你命3000”。但是這種飛彈攔截系統有一個缺陷:雖然它的第一發炮彈能夠到達任意的高度,但是以後每一發炮彈都不能高於前一發的高度。某天,雷達捕捉到修羅王軍團的飛彈來襲。由於該系統還在試用階段,所以只有一套系統,因此有可能不能攔截所有的飛彈。
輸入飛彈依次飛來的高度(雷達給出的高度資料是不大於30000 的正整數),計算這套系統最多能攔截多少飛彈和如果要攔截所有飛彈最少要配備多少套這種飛彈攔截系統。輸入一行,為飛彈依次飛來的高度輸出行,分別是最多能攔截的飛彈數與要攔截所有飛彈最少要配備的系統數範例輸入
389 207 155 300 299 170 158 65
範例輸出
62
解題思路:題目所給的資料並不知道數量,所以添加一個字元,genchar()擷取字元判斷是不是空格,是空格說明後面還有資料,繼續讀入整數。
char cc; cin>>a[n++]; while((cc=getchar())==‘ ‘){ cin>>a[n++]; }
本來我是用的cc=getchar()!=‘\n’,結果提交oj,顯示逾時,程式根本停不下。所以不知道一行的最後用什麼結束的,但改成只要不等於空格就結束,就可以了。
最多能攔截的飛彈數很容易明白,就是求最長非遞增子序列。
最少要配備的系統數,剛開始我以為只要後面一個數比前面一個數大,然後c++,最後得到的就是要配備的系統數呢。
但7 8 9 2 1 3 4 5這幾個數就不可以,得到的是5,但結果應該是4。 5雖然比4大,但是他可以被打掉9的飛彈打掉。所以5就不用再計入了。
後來百度一下,應該是求最長遞增子序列才行。
然後證明這個好像是什麼dilworth定理(最少鏈劃分 = 最長反鏈長度)。
這個還不太懂,一會再看看。
還有個理解的方法,這個序列可以挑出很多遞增子序列來,找一個不是最長的,再看他後面一定還有一個比這個序列中大的一個數,這個數也要用一個飛彈。所以得找最長遞增子序列才能打掉所有飛彈。
代碼:
#include <iostream>#include <cstdio>using namespace std;int main(){ int n=0; int a[10000]; int sum[10000]; int sum2[10000]; int c=0;//儲存下一個高度比上一個高度大的情況數量 int maxx; int maxx2; int ans=1; int ans2=1; char cc; cin>>a[n++]; while((cc=getchar())==‘ ‘){ cin>>a[n++]; } sum[0]=1; sum2[0]=1; for(int i=1;i<n;i++){ maxx=0; maxx2=0; for(int j=0;j<i;j++){ if(a[j]>=a[i]){ maxx=max(maxx,sum[j]); } if(a[j]<a[i]){ maxx2=max(maxx2,sum2[j]); } } sum[i]=maxx+1; ans=max(ans,sum[i]); sum2[i]=maxx2+1; ans2=max(ans2,sum2[i]); } printf("%d\n%d",ans,ans2); return 0;}
【動態規劃】攔截飛彈_dilworth定理_最長遞增子序列