拦截导弹 动态规划 LDS

LDS<最长下降子序列>
定义

Longest Decreasing Subsequence
Given an array of N integers, find the length of the longest subsequence of a given sequence such that all elements of the subsequence are sorted in strictly decreasing order.

Examples :

Input: arr[] = [15, 27, 14, 38, 63, 55, 46, 65, 85]
Output: 3
Explanation: The longest decreasing sub sequence is {63, 55, 46}

Input: arr[] = {50, 3, 10, 7, 40, 80}
Output: 3
Explanation: The longest decreasing subsequence is {50, 10, 7}

Note:

子序列不同于子串,子串必须连续,子序列不必连续

动态规划思路:

Let arr[0..n-1] be the input array and lds[i] be the length of the LDS ending at index i such that arr[i] is the last element of the LDS.
Then, lds[i] can be recursively written as:
lds[i] = 1 + max(lds[j]) where i > j > 0 and arr[j] > arr[i] 
or
lds[i] = 1, if no such j exists.
简单的想,我们可以吧lds[i]定义为以arr[i]为结尾的最长递减子序列的长度,
那么对于arr[i]:之前的所有可能存在的以arr[j]为结尾的最长递减子序列,(j < i)
只要arr[j] > arr[i],便可以把arr[i]加入到已存在的最长递减子序列后边。
如果不存在这样的最长递减子序列,那么我们便只好以arr[i]为头尾,
形成长度为1的以arr[i]结尾的最长递减子序列。
最后从lds[]中找到最大值便是整个数组的最长递减子序列的长度。
(当然我们可以进行优化,在计算lds[i]时,使用变量max比较max与lds[i]的值,实时更新max)

NOTE:其实思路与最长递增子序列的思路相同
题面:

题目内容:
某国为了防御敌国的导弹袭击,开发出一种导弹拦截系统。但是这种导弹拦截系统有一个缺陷:虽然它的第一发炮弹能够到达任意的高度,但是以后每一发炮弹都不能高于前一发的高度。某天,雷达捕捉到敌国的导弹来袭,并观测到导弹依次飞来的高度,请计算这套系统最多能拦截多少导弹。拦截来袭导弹时,必须按来袭导弹袭击的时间顺序,不允许先拦截后面的导弹,再拦截前面的导弹。
输入格式:
第一行,输入雷达捕捉到的敌国导弹的数量k(k<=25),第二行,输入k个正整数,表示k枚导弹的高度,按来袭导弹的袭击时间顺序给出,以空格分隔。
输出格式:
输出只有一行,包含一个整数,表示最多能拦截多少枚导弹。
输入样例:
8
300 207 155 300 299 170 158 65
输出样例:
6

可以看到这里其实并不是严格的递减序列,但我们可以借鉴最长递减子序列的思路

JAVA实现:

import java.util.Scanner;
// dfs version
/*public class Assignment_4_1 {
    private static int n, ans;
    private static int[] missiles;
    public static void main(String[] args) {
        Scanner cin = new Scanner(System.in);
        n = cin.nextInt();
        ans = 0;
        missiles = new int[n+2];
        for (int i = 1; i <= n; i++) {
            missiles[i] = cin.nextInt();
        }
        dfs(1, 0, Integer.MAX_VALUE);
        System.out.printf("%d", ans);

    }

    public static void dfs(int index, int cnt, int max) {
        if (index > n) {
            ans = Math.max(ans, cnt);
            return;
        }
        if (missiles[index] <= max) {
            dfs(index+1, cnt, max); // 不拦截第index枚导弹
            dfs(index+1, cnt+1, missiles[index]);   // 拦截第index枚导弹
        } else {
            dfs(index+1, cnt, max); // 不拦截第index枚导弹
            dfs(index+1, 1, missiles[index]);   // 拦截第index枚导弹
        }
    }
}*/
// dp version
public class Assignment_4_1 {
    private static int n;
    private static int[] missiles;
    public static void main(String[] args) {
        Scanner cin = new Scanner(System.in);
        n = cin.nextInt();
        missiles = new int[n];
        for (int i = 0; i < n; i++) {
            missiles[i] = cin.nextInt();
        }
        int ans = 0;
        int[] dp = new int[n];
        for (int i = 0; i < n; i++) {
            dp[i] = 1;
            for (int j = 0; j < i; j++) {
                if (missiles[j] >= missiles[i]) dp[i] = Math.max(dp[i], dp[j] + 1);
            }
            ans = Math.max(ans, dp[i]);
        }
        System.out.println(ans);
    }
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值