1260:【例9.4】攔截導彈(Noip1999)


題目來源:http://ybt.ssoier.cn:8088/problem_show.php?pid=1260

1260:【例9.4】攔截導彈(Noip1999)


時間限制: 1000 ms         內存限制: 65536 KB
提交數: 4533     通過數: 1660 

【題目描述】

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

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

 

【輸入】

輸入導彈依次飛來的高度。

【輸出】

第一行:最多能攔截的導彈數;

第二行:要攔截所有導彈最少要配備的系統數。

【輸入樣例】

389 207 155 300 299 170 158 65

【輸出樣例】

6
2

例題不怎么詳的解:
這是一道十分經典的LIS動規題目,難點和重點在於需要查找多條LIS並進行統計。這題說是dp,實則更像是純模擬。
我們抽絲剝繭,將本題數學框架討論如下:
首先我們要求的這個最多能攔截的導彈數,也就是給出序列的LIS,
然后是攔截所有導彈最少要配備的系統數,也就是最少有幾條公共子序列存在,注意,每條子序列必須是最優的。
這個最優是什么意思呢?也就是每套系統(每條子序列)必須攔截下最多的導彈(擁有最長最優的長度)。

本題的算法,我借鑒的是書上的解法,這個解法是可以優化空間復雜度的,但是因為我是初學者,所以寫出代碼后也不大懂優化,只能勉勉強強按書上的來。
第一問可以用dp解,第二問可以用貪心解。

算法分析:
設置a[j]代表原序列中第j個元素,b[j]表示長度為j的LIS,h[k]表示第k個系統當前可攔截導彈的最高高度;
  1. 遍歷已輸入序列一次,maxx暫存當前導彈高度可用最長LIS的長度值,於是當前輸入的導彈會使LIS長度maxx+1,並將此值存入b數組;
  2. 記錄最長LIS的長度;
  3. 貪心計算本次導彈由哪一套系統攔截,若當前所有LIS均對當前輸入導彈高度不可用,則新增一套系統攔截。
如果沒看懂也無妨,后面會詳細解釋。

重頭戲來了。

    先初始化。

 dp部分很簡單的:

 

1 maxx=0; 2 for(j=1;j<=i-1;j++) 3  if(a[j]>=a[i]&&b[j]>maxx) maxx=b[j]; 4 b[i]=maxx+1; 5 if(b[i]>m) m=b[i];

 

 大概就是每輸入一個數,遍歷一遍當前序列,找一遍當前可構成的不下降序列。

 當然如果僅僅是這樣就只能求出LIS,求不出最少的系統數,於是我們需要一個貪心:

 1 x=0;//當前使用的系統  2 for(k=1;k<=n;k++)  3  {  4         if(h[k]>=a[i])//首先你這個系統你得可用  5          if(x==0) x=k;  6          else if(h[k]<h[x]) x=k;//選擇當前可攔截高度最低的可用系統攔截  7  }  8     if(x==0){  9         n++;x=n; 10  } 11     h[x]=a[i];

 完美。

 樣例代碼:

#include<iostream> #include<cstdio> #include<cstring> #include<cmath> #include<algorithm> #include<string> #include<cstdlib> #include<queue> #include<vector>
#define INF 0x3f3f3f3f
#define PI acos(-1.0)
#define N 10010
#define MOD 2520
#define E 1e-12
/*This is an example*/
int i,j,k,x,n,maxx,m,a[N],b[N],h[N]; using namespace std; int main() { i=1;n=0;m=0; memset(a,0,sizeof(a)); memset(b,0,sizeof(b)); memset(h,0,sizeof(h)); while(cin>>a[i]) { maxx=0; for(j=1;j<=i-1;j++) if(a[j]>=a[i]&&b[j]>maxx) maxx=b[j]; b[i]=maxx+1; if(b[i]>m) m=b[i]; x=0; for(k=1;k<=n;k++) { if(h[k]>=a[i]) if(x==0) x=k; else if(h[k]<h[x]) x=k; } if(x==0){ n++;x=n; } h[x]=a[i]; i++; } cout<<m<<endl<<n<<endl; return 0; }

2019-05-03 12:34:13

 

 

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM