這是一道動態規划題,和昨天的取硬幣還有最長公共字串有點類似。
1.題目描述:
某國為了防御敵國的導彈襲擊,發展出一種導彈攔截系統。但是這種導彈攔截系統有一個缺陷:雖然它的第一發炮彈能夠到達任意的高度,但是以后每一發炮彈都不能高於前一發的高 度。某 天,雷達捕捉到敵國的導彈來襲。由於該系統還在試用階段,所以只有一套系統,因此有可能不能攔截所有的導彈。輸入導彈依次飛來的高度(雷達給出的高度數據是不大於30000的正整數),計算這套系統最多能攔截多少導彈,如果要攔截所有導彈最少要配備多少套這種導彈攔截系統。
輸入格式一行,為導彈依次飛來的高度。
輸出格式兩行,分別是最多能攔截的導彈數與要攔截所有導彈最少要配備的系統數。
2.樣例輸入
300 207 155 300 299 170 158 65
3.樣例輸出
6
2
4.算法思想:
我們遇到這道題目,我們自己算的話就是,先從300開始,然后比較207比300小能攔截,155比207小能攔截,65比155小能攔截,這一趟是能攔截4 個導彈。然后暴力求出每次最多能攔截的導彈數,再比較最大的,這是我們平時的暴力破解思維。但是,這樣想想要多少次循環,也太麻煩了。當然最后最多能攔截的是300 300 299 170 158 65這六種。我們應該想到動態規划,動態規划只是一種工具。這道題目怎么用到動態規划呢?動態規划其實就是填矩陣,之前在別的博客上看到求最長子序列的時候填的是二維數組,當然這題也一樣是。怎么填呢?在求最長公共子串時從頭開始遍歷,如果想等,則加1,不等則繼續是這個,這道題目呢如下,動態規划要從底部開始動態規划。
300 207 155 300 288 299 170 158 65
6 4 2 5 4 4 3 2 1
剛開始一直沒有思路,但是仔細想一下,發現我300比207大,最大序列加一,207比155大加1,但是300不比155大,這時候怎么辦,就要遞歸遍歷。但是我從末尾看,只要65是1個長度,只要158大於65,那么158肯定是第二個長度,170大於158,是第3個長度,299大於170,第4個長度,但是288沒有299大,前面比較,比170大,所以等於170的長度+1。300比299大,所以長度等於299的長度+1,155比65大,所以155等於65的長度+1,這就得到了狀態轉移方程。動態規划問題,不管是不是上升序列,都要進行判斷,這道題呢是怎么判斷的?這個導彈和之前的導彈比較,如果這個導彈比大於之前的並且它的temp值也是最大的,保存這個下標,然后讓temp[k] = temp[z] + 1,即得到了最后的結果,所以一定要搞清楚動態規划轉移方程。
具體代碼示例
package 藍橋杯; /* * 300 207 155 165 288 299 170 158 65 5 4 2 3 4 4 3 2 1 */ public class 導彈問題 { static int weizhi[] = {500,700,300,207,155,165,288,299,170,158,65}; public static void main(String[] args) { //記錄最大的位置 int temp[] = new int[weizhi.length]; temp[weizhi.length-1] = 1; f(temp,weizhi.length-2); //從第7個位置開始 for(int i=0;i<weizhi.length;i++) { System.out.println(temp[i]); } } private static void f(int[] temp, int k) { if(k==-1) { return; } int max=0; int z = 0; for(int i=k+1;i<=weizhi.length-1;i++) { if(weizhi[i]<weizhi[k]) { if(temp[i]>max) { max = temp[i]; z = i; } } temp[k] = temp[z]+1; f(temp, k-1); } } }