关于最长上升子序列问题的题目合集(动态规划、贪心、二分优化)

上升子序列(板子,二分优化)

int a[N];
int dp[N];
int main()
{   
    int len=0; 
    for(int i=1;i<=n;i++)
    {
        int l=0,r=len;
        int mid=(l+r+1)>>1;
        while(l<r)
        {
        if(dp[mid]<a[i])l=mid;
        else r=mid-1;
        }
        len=max(len,r+1);
        dp[r+1]=a[i];
    }
    cout<<len<<endl;
}

友好城市(贪心、动态规划)

有一条横贯东西的大河,河有笔直的南北两岸,岸上各有位置各不相同的N个城市。北岸的每个城市有且仅有一个友好城市在南岸,而且不同城市的友好城市不相同。每对友好城市都向政府申请在河上开辟一条直线航道连接两个城市,但是由于河上雾太大,政府决定避免任意两条航道交叉,以避免事故。编程帮助政府做出一些批准和拒绝申请的决定,使得在保证任意两条航道不相交的情况下,被批准的申请尽量多。

测试数据:                                答案:4
7        
22 4
2 6
10 3
15 12
9 8
17 17
4 2

 将数据两两存入pair数组中进行保存,可以对数组的first进行从小到大排序,对数组的second序列求最大上升子序列,题目要求航道不应交叉,对于每个first,在排好序的情况下,若其second有了交叉,则必须有所取舍,从中选一,当选的是最长上升子序列,则一定可以选出最多的航道。

代码如下:

#include<iostream>
#include<algorithm>
using namespace std;
typedef pair<int,int>A;
const int N = 2e5+10;
const int M = 1e6+10;
A a[N];
int dp[M];
bool cmp(A e,A r)
{
	return e.second<r.second;
}
int main()
{
	int n;cin>>n;
	for(int i=1;i<=n;i++)
	{
		int x,y;cin>>x>>y;dp[i]=1;
		a[i].first=x;a[i].second=y;
	}
	sort(a+1,a+1+n,cmp);
	int len=0; 
	for(int i=1;i<=n;i++)
	{
		int l=0,r=len;
		while(l<r)
		{
			int mid=(l+r+1)>>1;
			if(dp[mid]<a[i].first)l=mid;
			else r=mid-1;
		}
		len=max(len,r+1);
		dp[r+1]=a[i].first;
	}
	cout<<len;
} 

 拦截导弹(贪心,动态规划)

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

输入导弹依次飞来的高度,计算这套系统最多能拦截多少导弹,如果要拦截所有导弹最少要配备多少套这种导弹拦截系统。

 测试样例

389 207 155 300 299 170 158 65        答案:6   2                                          90 103 99 83 102 70 86 70 99 71       答案:5   3

计算最多能拦截多少导弹即是去求最长下降子序列的个数,拦截所有导弹最少要配置多少套即用贪心做法:

若所有序列结尾都小于当前导弹高度,即需要再配置一个设备。

若可以有序列结尾大于导弹高度,则找结尾最小的那个将导弹加入。

这里求最长下降子序列需要注意将数组反向。

#include<iostream>
#include<vector>
using namespace std;
const int N = 1e5+10;
int a[N];
int dp[N];
int g[N];
int main()
{
	int n=1;
	while(cin>>a[n])n++;
	int maxa=0;
	for(int i=n-1;i>=1;i--)
	{
		int l=0,r=maxa;
		while(l<r)
		{
			int mid=(l+r+1)/2;
			if(dp[mid]<=a[i])l=mid;//这里与模板不太一样,需要加一个等号,否则会出错。
			else r=mid-1;
		}
		maxa=max(maxa,l+1);
		dp[l+1]=a[i];
	}
	cout<<maxa<<endl;
	int cnt=0;vector<int>v;
	for(int i=1;i<=n-1;i++)
	{
		int j=0;
		while(j<v.size()&&v[j]<a[i])j++;
		if(j>=v.size())v.push_back(a[i]);
		else v[j]=a[i];
	}
	cout<<v.size();
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值