拦截导弹(最长非递减子序列)——动态规划

拦截导弹问题本质上是求最长非递增子序列的问题,采用动态规划解题时,可以划分为k(k为序列长度)个子问题,每个子问题就是求以第i(0<=i<k)个值为终点的最长非递增子序列。

一、题目描述

某国开发出一种导弹拦截系统,该系统有一个缺陷:虽然它的第一发炮弹能够到达任意的高度,但是以后每一发炮弹都不能高于前一发的高度。现在,捕获到一系列导弹依次飞来的高度,计算这套系统最多能拦截多少导弹。拦截来袭导弹时,必须按来袭导弹袭击的时间顺序,不允许先拦截后面的导弹,再拦截前面的导弹。

输入
第一行,输入雷达捕捉到的敌国导弹的数量k(k<=25),
第二行,输入k个正整数,表示k枚导弹的高度,按来袭导弹的袭击时间顺序给出,以空格分隔。
 
输出
输出只有一行,包含一个整数,表示最多能拦截多少枚导弹。

样例输入
8
300 207 155 300 299 170 158 65
样例输出
6

二、题目分析

注意到题目中描述后续每发炮弹的高度都不高于前一发炮弹,也就是说炮弹的高度是非递增的,而每发炮弹的高度必然与对应的来袭导弹的高度相等,此外,是可以放弃拦截某一枚导弹,直接拦截下一枚的。该问题则变成为了最长非递增子序列的问题。

采用动态规划解题,首先寻找该问题的子问题,满足最优子结构和无后效性。设某一枚导弹的高度为missile[i](i=0,1,……k),原问题可以看做是求以missile[i]为终点的最长非递增子序列的长度maxLen[i],所以需要进行k次计算,求出每一个maxLen[i]之后,再选择其中的最大值作为结果。

关于maxLen[i]的计算,在0到i之间寻找大于等于missile[i]的高度missile[j],每当满足该条件,则更新一次maxLen[i]的值
maxLen[i]=max(maxLen[i],maxLen[j]+1)

三、源代码

//  最长非递增子序列
//
#include <iostream>
#include <algorithm>
using namespace std;

int main()
{
	int k = 0;	//导弹数目
	int missile[25] = { 0 };//每发导弹的高度序列
	int maxLen[25];         
	cin >> k;
	for (int i = 0; i < k; ++i)
	{
		cin >> missile[i];
		maxLen[i] = 1;      //以missile[i]为终点的最长非增子序列,初始化为1
	}
		
	for (int i = 1; i < k; ++i)//依次以第i个数为序列终点,从第2个数开始
	{
		for (int j = 0; j < i; ++j) //寻找在i之前且大于missile[i]的数
			if (missile[j] >= missile[i])
				maxLen[i] = max(maxLen[i], maxLen[j] + 1);//更新以missile[i]为终点的最长非增子序列的长度
	}

	cout << *max_element(maxLen, maxLen + k)<<endl;//从k个结果中选出最大的
	return 0;
}
发布了13 篇原创文章 · 获赞 7 · 访问量 591

猜你喜欢

转载自blog.csdn.net/hejnhong/article/details/105160361