怪盜基德的滑翔翼
怪盜基德是一個充滿傳奇色彩的怪盜,專門以珠寶爲目標的超級盜竊犯。而他最爲突出的地方,就是他每次都能逃脫中村警部的重重圍堵,而這也很大程度上是多虧了他隨身攜帶的便於操作的滑翔翼。
有一天,怪盜基德像往常一樣偷走了一顆珍貴的鑽石,不料卻被柯南小朋友識破了僞裝,而他的滑翔翼的動力裝置也被柯南踢出的足球破壞了。不得已,怪盜基德只能操作受損的滑翔翼逃脫。
假設城市中一共有N幢建築排成一條線,每幢建築的高度各不相同。初始時,怪盜基德可以在任何一幢建築的頂端。他可以選擇一個方向逃跑,但是不能中途改變方向(因爲中森警部會在後面追擊)。因爲滑翔翼動力裝置受損,他只能往下滑行(即:只能從較高的建築滑翔到較低的建築)。他希望儘可能多地經過不同建築的頂部,這樣可以減緩下降時的衝擊力,減少受傷的可能性。請問,他最多可以經過多少幢不同建築的頂部(包含初始時的建築)?
Input
輸入數據第一行是一個整數K,代表有K組測試數據。
每組測試數據包含兩行:第一行是一個整數N,代表有N幢建築。第二行包含N個不同的整數,每一個對應一幢建築的高度h,按照建築的排列順序給出。
Output
對於每一組測試數據,輸出一行,包含一個整數,代表怪盜基德最多可以經過的建築數量。
Sample Input
3
8
300 207 155 299 298 170 158 65
8
65 158 170 298 299 155 207 300
10
2 1 3 4 5 6 7 8 9 10
Sample Output
6
6
9
Range
N < 100;
0 < h < 10000;
K < 100.
Analvsis
這一題其實是最長上生序列與最長下降序列的結合,需要求出最長上升序列的長度,與最小下降序列的長度,輸出較大的那一個。
(我第一次做的時候,就只求了最長下降序列並輸出,不幸答案錯誤%>_<%)
此爲其一,其二,此題有多組測試數據,所以每一次使用數組後,養成一個好習慣,把數組清零。
下面是清零函數及所需頭文件(一維,二維需要循環清零);
b[i](狀態)是表示從第i個開始最長的下降或上升序列;
h[i]表示第i個的高度
memset(b,0,sizeof(b));//#include<cstring>
memset(h,0,sizeof(h));
有了狀態,狀態轉移方程式就有了
b[i]=max(b[j]+1,b[i]);
於是 ·············································
就有了代碼的核心部分
1.求最長下降序列
for(int i=2;i<=k;i++)
for(int j=1;j<i;j++)
if(h[j]>h[i])
b[i]=max(b[j]+1,b[i]);
2.最長上升序列
for(int i=k-1;i>=1;i--)
for(int j=k;j>i;j--)
if(h[j]>h[i])
b[i]=max(b[j]+1,b[i]);
接下來,我們發現 (⊙o⊙)…
怎麼找到這個最長下降序列(上升序列)呀?
其實,只需要一個函數即可(或用循環枚舉每一個,找出最大的)
*max_element(b+1,b+k+1)+1;//b數組第1個下標開始到第k個數中,從中選出最大的數。
有了這些,代碼也可以實現了!!!
Code
#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
int b[5005],h[5005];
int main()
{
int p;
scanf("%d",&p);
for(int l=1;l<=p;l++)
{
memset(b,0,sizeof(b));
memset(h,0,sizeof(h));
int k;
scanf("%d",&k);
for(int q=1;q<=k;q++)
scanf("%d",&h[q]);
for(int i=2;i<=k;i++)
for(int j=1;j<i;j++)
if(h[j]>h[i])
b[i]=max(b[j]+1,b[i]);
int s1=*max_element(b+1,b+k+1)+1;
memset(b,0,sizeof(b));
for(int i=k-1;i>=1;i--)
for(int j=k;j>i;j--)
if(h[j]>h[i])
b[i]=max(b[j]+1,b[i]);
int s2=*max_element(b+1,b+k+1)+1;
printf("%d\n",max(s1,s2));
}
return 0;
}