1. 程式人生 > >最少攔截系統 (序列型dp)

最少攔截系統 (序列型dp)

某國為了防禦敵國的導彈襲擊,發展出一種導彈攔截系統.但是這種導彈攔截系統有一個缺陷:雖然它的第一發炮彈能夠到達任意的高度,但是以後每一發炮彈都不能超過前一發的高度.某天,雷達捕捉到敵國的導彈來襲.由於該系統還在試用階段,所以只有一套系統,因此有可能不能攔截所有的導彈. 
怎麼辦呢?多搞幾套系統唄!你說說倒蠻容易,成本呢?成本是個大問題啊.所以俺就到這裡來求救了,請幫助計算一下最少需要多少套攔截系統. 

Input

輸入若干組資料.每組資料包括:導彈總個數(正整數),導彈依此飛來的高度(雷達給出的高度資料是不大於30000的正整數,用空格分隔) 

Output

對應每組資料輸出攔截所有導彈最少要配備多少套這種導彈攔截系統. 

Sample Input

8 389 207 155 300 299 170 158 65

Sample Output

2

思路:

       問題一最多能攔截多少個導彈,其實就是找出最長不連續不上升序列,

       問題二需要配備多少套,我們把第二問的問題抽象出來,那就是:把一個數列劃分成最少的最長不升子序列。

度娘定理:
Dilworth定理:對於一個偏序集,最少鏈劃分等於最長反鏈長度。
Dilworth定理的對偶定理:對於一個偏序集,其最少反鏈劃分數等於其最長鏈的長度。
 也就是說把一個數列劃分成最少的最長不升子序列的數目就等於這個數列的最長上升子序列的長度。

程式碼:

//求最長非遞減子序列的長度 
#include<iostream>
using namespace std;
int n,a[30005];
int dp[30005];
int main()
{
	while(~scanf("%d",&n))
	{
		for(int i=0;i<n;i++)
	        dp[i]=1;
	    for(int i=0;i<n;i++)
	        cin>>a[i];
	    for(int i=0;i<n;i++)
	    {
	    	for(int j=0;j<i;j++)
	    	{
	    		if(a[i]>a[j]&&dp[j]+1>dp[i])
	    		    dp[i]=dp[j]+1;
			}
		}
		int maxx=0;
		for(int i=0;i<n;i++)
		   maxx=max(maxx,dp[i]);
		cout<<maxx<<endl;
	}
	return 0;
}