問題鏈接:Vijos P1303 導彈攔截
背景
實中編程者聯盟爲了培養技術精湛的後備人才,必須從基礎題開始訓練。
描述
某國爲了防禦敵國的導彈襲擊,研發出一種導彈攔截系統。但是這種導彈攔截系統有一個缺陷:雖然它的第一發炮彈能夠到達任意的高度,但是以後每一發炮彈都不能高於前一發的高度。某天,雷達捕捉到敵國的導彈來襲。由於該系統還在試驗階段,所以只有一套系統,因此有可能不能攔截所有的導彈。
格式
輸入格式
輸入數據只有一行,該行包含若干個數據,之間用半角逗號隔開,表示導彈依次飛來的高度(導彈最多有 20 枚,其高度爲不大於 30000 的正整數)。
輸出格式
輸出數據只有一行,該行包含兩個數據,之間用半角逗號隔開。第一個數據表示這套系統最多能攔截的導彈數;第二個數據表示若要攔截所有導彈至少要再添加多少套這樣的系統。
樣例1
樣例輸入1
389,207,155,300,299,170,158,65
樣例輸出1
6,1
限制
每個測試點限時 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;
}