Vijos P1303 導彈攔截【最長上升子序列+DP】

問題鏈接:Vijos P1303 導彈攔截

 

背景

實中編程者聯盟爲了培養技術精湛的後備人才,必須從基礎題開始訓練。

描述

某國爲了防禦敵國的導彈襲擊,研發出一種導彈攔截系統。但是這種導彈攔截系統有一個缺陷:雖然它的第一發炮彈能夠到達任意的高度,但是以後每一發炮彈都不能高於前一發的高度。某天,雷達捕捉到敵國的導彈來襲。由於該系統還在試驗階段,所以只有一套系統,因此有可能不能攔截所有的導彈。

格式

輸入格式

輸入數據只有一行,該行包含若干個數據,之間用半角逗號隔開,表示導彈依次飛來的高度(導彈最多有 20 枚,其高度爲不大於 30000 的正整數)。

輸出格式

輸出數據只有一行,該行包含兩個數據,之間用半角逗號隔開。第一個數據表示這套系統最多能攔截的導彈數;第二個數據表示若要攔截所有導彈至少要再添加多少套這樣的系統。

樣例1

樣例輸入1

389,207,155,300,299,170,158,65

Copy

樣例輸出1

6,1

Copy

限制

每個測試點限時 1 秒。

提示

注意申題,切勿直接提交過去的程序!

來源

NOIP1999 經典問題 [實中編程者聯盟 2006.10]

 

問題分析:

第一問:每一發導彈都不能高於前一發,也就是低於或等於前一發導彈,最多可以攔截的導彈數,也就是從左往右求最長下降子序列。用dp[i]表示到i位置最多攔截了多少,對於每個節點,掃面他前面i-1個節點,如果大於dp[i],就用dp[j]+1替換,不然還是dp[i].

第二問 :  要增加的系統數,先求總共要求的系統數,就是求從左往右最長上升子序列,因爲f[i]表示到i位置前i個需要多少系統,對於當前節點,掃描前面的所有節點,如果比現在的小,這時就要更新當前節點,f[i]是在前面的基礎上選最大的+1,問的是要增加的數量最後要減1。

注意要輸入標點符號。

#include <iostream>
using namespace std;
 
int a[100],f[100], dp[100], n;
 
int res(int n)//求最長上升子序列 
{
	int s=0;
	for(int i=0;i<n;i++)
	{
		f[i]=1;//爲f[i]設置初值,最初只包含a[i] 
		for(int j=0;j<i;j++)
		{
			if(a[j]<a[i])
			{
				f[i]=max(f[i],f[j]+1);
			}
		}
		s=max(s,f[i]);//記錄f[i]的最大值 
	}
	return s;
}
 
int lds(int n)//求最長下降子序列 
{
	int s=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);
			}
		}
		s=max(s,dp[i]);
	}
	return s;
}
 
int main()
{
    char ch;
    n = 0;
    while(scanf("%d%c", &a[n++], &ch))
        if(ch == '\n')
             break;
    cout << lds(n) << "," <<res(n) - 1 << endl;
 
    return 0;
}
發佈了52 篇原創文章 · 獲贊 8 · 訪問量 7099
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章