STL--lower_bound和upper_bound及其cmp用法 例题-导弹拦截 上升序列下降序列原理求法

UPPER_BOUND LOWER_BOUND的CMP一些用法·

数列为升序时:

	int a[20] = { 1,1,2,2,3,3,4,4,5,6,7,7,7 };
	cout << "返回第一个大于等于x的地址:\n";
	cout << *lower_bound(a, a + 13, 3) << endl;//值
	cout << lower_bound(a, a + 13, 3) - a<< endl;//位置
	cout << "返回第一个大于x的地址:\n";
	cout << *upper_bound(a, a + 13, 3) << endl;//值
	cout << upper_bound(a, a + 13, 3) - a << endl;//位置
返回第一个大于等于x的地址:
3
4
返回第一个大于x的地址:
4
6

 数列为降序时:

	bool cmp(int x, int y)
    {
	    return x > y;
    }

    int a[20] = { 7,7,6,5,5,4,4,3,3,2,2,1,1 };
	cout << "返回第一个小于等于x的地址:\n";
	cout << *lower_bound(a, a + 13, 3, cmp) << endl;//值
	cout << lower_bound(a, a + 13, 3, cmp) - a << endl;//位置
	cout << "返回第一个小于x的地址:\n";
	cout << *upper_bound(a, a + 13, 3, cmp) << endl;//值
	cout << upper_bound(a, a + 13, 3, cmp) - a << endl;//位置
返回第一个小于等于x的地址:
3
7
返回第一个小于x的地址:
2
9

题目描述

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

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

输入格式

11行,若干个整数(个数\le 100000≤100000)

输出格式

22行,每行一个整数,第一个数字表示这套系统最多能拦截多少导弹,第二个数字表示如果要拦截所有导弹最少要配备多少套这种导弹拦截系统。

输入输出样例

输入 #1

389 207 155 300 299 170 158 65

输出 #1

6
2

说明/提示

为了让大家更好地测试n方算法,本题开启spj,n方100分,nlogn200分

每点两问,按问给分。

原理解释:Dilworth定理的对偶定理:对于一个偏序集,其最少反链划分数等于其最长链的长度。也就是求数列的最长降序子序列的长度及最长升序子序列的长度。

n2方法:动态规划

#include<iostream>
using namespace std;
int a[50005];
int n = 0;
int f[50005], g[50005];
int maxup = -1, maxdown = -1;
int main()
{
	while (cin >> a[++n]);
	n--;
	for (int i = 1; i <= n; i++)
	{
		f[i] = g[i] = 1;
		for (int j = 1; j < i; j++)
		{
			if (a[j] >= a[i])
				f[i] = max(f[i], f[j] + 1);

			if (a[j] < a[i])
				g[i] = max(g[i], g[j] + 1);
		}
		if (f[i] > maxup)
			maxup = f[i];
		if (g[i] > maxdown)
			maxdown = g[i];
	}
	cout << maxup << "\n" << maxdown;
	return 0;
}

这个方法相当于对每一个i上的最长序列都求出来了,因此可以解决一些对时间复杂度要求不太高但是对每一位都要参与的最长序列的问题

比如稍作修改:大朋友的数字 - 洛谷

#include<iostream>
using namespace std;
int a[10005];
int f[10005], v[10005];
int main()
{
	int n;
	cin >> n;
	for (int i = 1; i <= n; i++)
	{
		cin >> a[i];
		v[i] = a[i];
		f[i] = 1;
		if (i == 1)
		{
			cout << v[i] << " ";
			continue;
		}
		for (int j = 1; j < i; j++)
		{
			if (a[i] >= a[j])
				if (f[j] + 1 > f[i])
				{
					f[i] = f[j] + 1;
					v[i] = v[j] + a[i];
				}
		}
		cout << v[i] << " ";
	}
	return 0;
}

nlogn方法

#include<iostream>
#include<algorithm>
using namespace std;
const int Size = 100000 + 5;
int a[Size], b[Size], c[Size];
bool cmp(int a, int b)
{
	return a > b;
}
int main()
{
	int n = 0;
	while (cin >> a[++n]);
	n--;
	int len1 = 0, len0 = 0;
	b[0] = 98989888;
	c[0] = -1;
	for (int i = 1; i <= n; i++)
	{
		//如果a[i]小于等于栈顶,入栈.
		//如果a[i]比栈顶的大,找到栈中第一个比他小的数,
		//用它把这个数覆盖掉.
		if (a[i] <= b[len1])
		{
			len1++;
			b[len1] = a[i];
		}
		else
		{
			int t = upper_bound(b + 1, b + 1 + len1, a[i], cmp) - b;
			b[t] = a[i];
		}
		//反之,亦同理
		//根据××定理这里不能有等号
		if (a[i] > c[len0])
		{
			len0++;
			c[len0] = a[i];
		}
		else
		{
			int s = lower_bound(c + 1, c + 1 + len0, a[i]) - c;
			c[s] = a[i];
		}
	}
	cout << len1 << "\n" << len0;
	return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值