最长不降子序列&导弹拦截问题

Written with StackEdit.

问题描述

设有一个正整数的序列:??,??,…,??,对于下标??<??<…<??,若有???≤???≤…≤??? ,则称存在一个长度为m的不下降序列。
给出序列,求最长不降序列的长度.

思路

创建数组f[],用f[i]表示长度为i的最长不下降子序列的尾值,那么f[]数组一定是一个有序序列。用变量t表示数组f[]的长度,那么t的值就是最长不下降子序列的长度
对每一个输入的数a[i]进行如下操作:

  • 判断a[i]是否大于f[t],
    • 如果大于f[t],那么就说明现在存在一个长度为t的不下降子序列,且这个子序列的尾值比a[i]小,那么如果将a[i]接在这个子序列后面,就可以得到一个长度为t+1的最长不下降子序列,那么就可以通过a[i]更新f[]数组
    • 如果a[i]不大于f[t],那么在f[]数组中一定存在大于等于a[i]的数,找到一个k,使得f[k]为f[]数组中大于等于a[i]的数中最小的。那么f[k-1]定小于a[i],这说明已经存在了一个长度为k-1的序列,而且这个序列的尾值小于a[i]。如果将a[i]接在这个序列后面就可以构成一个新的长度为k的最长不下降子序列,而且这个子序列的尾值小于f[k],那么就可以用a[i]来更新f[k]
      EXP:维护一个数组d,d[i]为长度为i的不降子序列.
  • 如果新接收元素大于末尾的元素d[len],则列为len+1个元素,更新;
  • 如果小于,则更新序列d中第一个不小于该元素的.

示例代码

'''
@Description:最长不降子序列
@Date: 2019-10-26 15:53:18
@Author: I-Hsien
@LastEditors: I-Hsien
@LastEditTime: 2019-10-27 16:21:14
'''
if __name__=="__main__":
	array=input().split()
	upset=[int(array[0])]#Initilize the set by the first member in array.
	for i in range(1,len(array)):#Skip array[0]
		if int(array[i])>=upset[-1]:#如果是严格单调就没有=
			upset.append(int(array[i]))
		else:
			for j in range(len(upset)):
			if upset[j]>int(array[i]):#如果是严格单调就要加=:想想看为什么(不能使set产生非严格单调情况)
			upset[j]=int(array[i])
			break
print(len(upset))#Return maxium length

E.g.

See https://blog.csdn.net/Liao_Jingyi/article/details/35568185

某国为了防御敌国的导弹袭击,发展出一种导弹拦截系统。但是这种导弹拦截系统有一个缺陷:虽然它的第一发炮弹能够到达任意的高度,但是以后每一发炮弹都不能高于前一发的高度。某天,雷达捕捉到敌国的导弹来袭。由于该系统还在试用阶段,所以只有一套系统,因此有可能不能拦截所有的导弹。

输入导弹依次飞来的高度(雷达给出的高度数据是不大于30000的正整数),计算这套系统最多能拦截多少导弹,如果要拦截所有导弹最少要配备多少套这种导弹拦截系统。

样例:
389 207 155 300 299 170 158 65
6(最多能拦截的导弹数)
2(要拦截所有导弹最少要配备的系统数)

第一个问题是求最长非上升子序列.
第二个问题想到的是求完最长非升子序列之后删除元素再求一遍.但这样只是局部解.

举个反例:6 1 7 3 2 错解:6 3 2/1/7 正解:6 1/7 3 2

想到最长上升子序列.
最长上升子序列中每两个元素之间可以认为是一个[转折点],比如实例中155-300,这时候就要新部署一套…

代码

'''
@Description: 
@Date: 2019-10-27 10:54:21
@Author: I-Hsien
@LastEditors: I-Hsien
@LastEditTime: 2019-10-27 16:54:41
'''
if __name__=="__main__":
    array=input().split()
    #1.最长非上升
    minset=[int(array[0])]
    for i in range(1,len(array)):
        if int(array[i])<=minset[-1]:
            minset.append(int(array[i]))
        else:
            for j in range(len(minset)):
                if int(array[i])>minset[j]:
                    minset[j]=int(array[i])#Update
                    break
    #Return len(minset)
    #2. 最长上升
    maxset=[int(array[0])]
    for i in range(1,len(array)):
        if int(array[i])>maxset[-1]:
            maxset.append(int(array[i]))
        else:
            for j in range(len(maxset)):
                if int(array[i])<=maxset[j]:
                    maxset[j]=int(array[i])#Update
                    break
    #Return len(maxset)
    print(len(minset),len(maxset))
发布了80 篇原创文章 · 获赞 13 · 访问量 2万+

猜你喜欢

转载自blog.csdn.net/POTASSIUM711/article/details/102768678