某國爲了防禦敵國的導彈襲擊,發展出一種導彈攔截系統.但是這種導彈攔截系統有一個缺陷:雖然它的第一發炮彈能夠到達任意的高度,但是以後每一發炮彈*都不能超過前一發的高度*.某天,雷達捕捉到敵國的導彈來襲.由於該系統還在試用階段,所以只有一套系統,因此有可能不能攔截所有的導彈.
怎麼辦呢?多搞幾套系統唄!你說說倒蠻容易,成本呢?成本是個大問題啊.所以俺就到這裏來求救了,請幫助計算一下最少需要多少套攔截系統.
Input
輸入若干組數據.每組數據包括:導彈總個數(正整數),導彈依此飛來的高度(雷達給出的高度數據是不大於30000的正整數,用空格分隔)
Output
對應每組數據輸出攔截所有導彈最少要配備多少套這種導彈攔截系統.
Sample Input
8 389 207 155 300 299 170 158 65
Sample Output
2
O(n^2)算法
一個數列的最長不上升子序列的數目等於該數列最長上升子序列的長度。
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int maxn = 30010;
int dp[maxn], a[maxn];
//dp[i]表示以a[i]爲結尾的的最長上升子序列
//有兩種情況:以a[i]結尾的上升子序列是
//1.只包含a[i],也就是dp[i]等於1;
//2.在滿足j<i且aj<ai的以a[i]爲結尾的上升子列末尾,追加上a[i]後得到的子序列
//dp[i]=max(1,dp[j]+1);
int main()
{
int n;
while(scanf("%d",&n)!=EOF)
{
for(int i=0;i<n;++i)
scanf("%d",&a[i]);
int ans=0;
for(int i=0;i<n;++i)
{
dp[i]=1;
for(int j=0;j<i;++j)
{
if(a[j]<a[i])
dp[i] = max(dp[i], dp[j]+1);
}
//若在i前面找不到一個比a[i]小的數說明a[i]與前面的數構成了一個子序列此時dp[i]仍等於1
//若能找到,說明又是另一個子序列,這時dp[i]就要變成找到的那個數的dp[j]+1了
ans=max(dp[i],ans);
}
printf("%d\n",ans);
}
return 0;
}
O(nlogn)算法:
//二分思想
//dp[i]表示長度爲i+1的上升子序列末尾元素最小值
//dp初始化爲INF很大的數
// 然後由前到後逐個考慮數列的元素,
//對於每個aj,如果i=0或者dp[i-1]<aj的話,
//就用dp[i]=min(dp[i],aj)進行更新。
//最終找出第一個大於等於INF的數的位置就是結果了
#include <cstdio>
#include <algorithm>
#define INF 0x3f3f3f
using namespace std;
int dp[30010],a[30010];
int main()
{
int n,i,j;
while(scanf("%d",&n)!=EOF)
{
for(i=0;i<n;++i)
{
scanf("%d",&a[i]);
dp[i]=INF;
}
/*fill(dp,dp+n,INF);*/
for(i=0;i<n;++i)
*lower_bound(dp,dp+n,a[i])=a[i];
//循環到最後在dp[]這個數組裏會存有數和INF,
//有幾個數就說明原來數組a[]中最少
//有幾個有序子數列(即每一個子數列都是我們能夠找到的最長的)
// 這幾個數是每一個子數列的最小的元素
printf("%d\n",lower_bound(dp,dp+n,INF)-dp);
//lower_bound()這個函數得到的不是數,而是數的地址,
//但他不是數組的下標,讓他減去首地址纔是下標
}
return 0;
}