问题 1627: [蓝桥杯][算法训练VIP]拦截导弹( LIS + STL)

题目连接:https://www.dotcpp.com/oj/problem1627.html
来源:C语言网

题目描述
  某国为了防御敌国的导弹袭击,发展出一种导弹 拦截系统。但是这种导弹拦截系统有一个缺陷:虽然它的第一发炮弹能够到达任意的高度,但是以后每一发炮弹都不能高于前一发的高度。某天,雷达捕捉到敌国的 导弹来袭。由于该系统还在试用阶段,所以只有一套系统,因此有可能不能拦截所有的导弹。
  输入导弹依次飞来的高度(雷达给出的高度数据是不大于30000的正整数),计算这套系统最多能拦截多少导弹,如果要拦截所有导弹最少要配备多少套这种导弹拦截系统。
输入
  一行,为导弹依次飞来的高度
输出
  两行,分别是最多能拦截的导弹数与要拦截所有导弹最少要配备的系统数
样例输入
  389 207 155 300 299 170 158 65
样例输出
  6
  2

  思路一:输入坑死…,我们可以发现最多能够拦截的导弹就是最长不上升子序列的个数,要拦截所有的导弹就是最长上升子序列,因为要把序列分成若干段不上升的,那么段与段之间一定存在上升,所以我们找到最长上升子序列就可以拦截到所有的导弹。 d p [ i ] dp[i] dp[i] 用来表示以 i i i 结尾的最长不上升/上升子序列的长度。

#include<bits/stdc++.h>
using namespace std;

typedef long long ll;
const int maxn=3e4+10;
int a[maxn],dp[maxn],dp1[maxn];//以i结尾的最长不上升子序列的长度 

int main(){
	//char b='a'; 
	int n=0;
	/*while(b!='\n'){
		scanf("%d",&a[n++]);
		b=getchar();
	}*/
	while(~scanf("%d",&a[n])) n++;
	//for(int i=0;i<n;i++) cout<<a[i]<<" ";
	int mmax1=-1,mmax2=-1;
	for(int i=0;i<n;i++){//当前数 
		dp[i]=1; dp1[i]=1;
		for(int j=0;j<i;j++){
			if(a[i]<=a[j]) dp[i]=max(dp[i],dp[j]+1);
			else dp1[i]=max(dp1[i],dp1[j]+1);
		}
		mmax1=max(mmax1,dp[i]);
		mmax2=max(mmax2,dp1[i]);
	}
	printf("%d\n%d\n",mmax1,mmax2);
	return 0;
} 

  思路二:对于上述问题,其实我们可以优化,用 d p [ i ] dp[i] dp[i] 来表示长度为 i i i 的末尾是 d p [ i ] dp[i] dp[i]

  对于不上升的子序列来说,这个末尾就是一个最大的末尾

  • 300 200 100 假如第三个数是200,那么此时 d p [ i ] dp[i] dp[i] 的末尾就是 200(因为要保证最长),通过 lower_bound 找到 <=200 的第一个数,然后用来代替 100

  对于上升的子序列来说,这个末尾就是一个最小的末尾

  • 100 300 假如第三个数是200,那么此时那么此时 d p [ i ] dp[i] dp[i] 的末尾就是 200(因为要保证最长),通过 lower_bound 找到 >=200 的第一个数,然后用来替代 300
#include<bits/stdc++.h>
using namespace std;

typedef long long ll;
const int maxn=1e3+10;
int a[maxn],dp[maxn],dp1[maxn];//表示长度为i的最小末尾是dp[i]

int main(){
	//char b='a'; 
	int n=0;
	/*while(b!='\n'){
		scanf("%d",&a[n++]);
		b=getchar();
	}*/
	while(~scanf("%d",&a[n])) n++;
	int len=0,len1=0;
	dp[len++]=dp1[len1++]=a[0];
	for(int i=1;i<n;i++){
		if(a[i]<=dp[len-1]) dp[len++]=a[i];
		else{
			int inx=lower_bound(dp,dp+len,a[i],greater<int>())-dp;
			dp[inx]=a[i];
		}
		if(a[i]>dp1[len1-1]) dp1[len1++]=a[i];
		else{
			int inx=lower_bound(dp1,dp1+len1,a[i])-dp1;
			dp1[inx]=a[i];
		}
	}
	printf("%d\n%d\n",len,len1);
	return 0;
} 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值