1. 程式人生 > >p1020導彈攔截

p1020導彈攔截

name 個數 證明 class cnblogs 炮彈 stream 整數 print

傳送門

P1020導彈攔截

題目描述

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

輸入導彈依次飛來的高度(雷達給出的高度數據是不大於30000的正整數),計算這套系統最多能攔截多少導彈,如果要攔截所有導彈最少要配備多少套這種導彈攔截系統。

輸入輸出格式

輸入格式:

一行,若幹個正整數最多100個。

輸出格式:

2行,每行一個整數,第一個數字表示這套系統最多能攔截多少導彈,第二個數字表示如果要攔截所有導彈最少要配備多少套這種導彈攔截系統。

輸入輸出樣例

輸入樣例#1:
389 207 155 300 299 170 158 65
輸出樣例#1:
6
2

【思路】
最長下降子序列
最長上升子序列
證明第二問:下面是網上幾位dalao的證法...都有道理的樣子....
(1)

二分圖最小路徑覆蓋
對於i導彈不低於j導彈的情況我們連一條邊i->j,然後題目可以轉成一張圖。
然後我們就可以求最小路徑覆蓋了=點數-最大匹配數
(2)最少鏈劃分 = 最長反鏈長度 所以最少多少套系統= 最長導彈高度上升 序列長度
因為我們要劃分盡量少的下降的鏈 就等於 最長的上升的臉的長度
【code】
#include<iostream>
#include
<cstdio> using namespace std; int n,ans,ans1; int dp[25],dpp[25],a[25]; int main() { while(scanf("%d",&a[++n])) for(int i=1;i<=n;i++) { for(int j=1;j<i;j++) { if(a[j]>a[i]) { dp[i]=max(dp[i],dp[j]+1
); ans=max(ans,dp[i]); } else if(a[j]<a[i]) { dpp[i]=max(dpp[i],dpp[j]+1); ans1=max(ans1,dpp[i]); } } } printf("%d\n%d",ans+1,ans1+1); return 0; }



p1020導彈攔截