187. 导弹防御系统

16 篇文章 0 订阅
9 篇文章 0 订阅

acwing187

题意

为了对抗附近恶意国家的威胁,R 国更新了他们的导弹防御系统。
一套防御系统的导弹拦截高度要么一直 严格单调 上升要么一直 严格单调 下降。
例如,一套系统先后拦截了高度为 3 和高度为 4 的两发导弹,那么接下来该系统就只能拦截高度大于 4 的导弹。
给定即将袭来的一系列导弹的高度,请你求出至少需要多少套防御系统,就可以将它们全部击落。

思路

一般的最长递增子序列问题中,系统要么只能一直递增,要么只能一直递减。而此题中是导弹拦截系统可以选择一直上升,也可以选择一直下降,当然一个系统只能二者取一。且要求击落所有导弹,单纯的最长递增子序列已经不再适用。

此题的解法是DFS最优剪枝+贪心

贪心

以最长上升子序列为例:
假设当前已经存在了n条单调上升的子序列, 每个序列最大的一个数(即最后一个数)为 d i d_i di 。假设 d i d_i di按从小到大的顺序排列。现在加入一个数x,最优解是:将x加入到第一个小于x的队列中
例如:1 3 4 7 9 , x = 5,则加入到 d i = 4 d_i = 4 di=4 的队列中。
若没有找打这样的数,则新建一个上升序列。

DFS
  1. 设置两个数组:
  • up:记录单调上升子序列的末尾元素,也即上面提到的 d i d_i di。此数组中的数是按从大到小的顺序排列的。
  • down:记录单调下降子序列的末尾元素,也即上面提到的 d i d_i di。此数组中的数是按从小到大的顺序排列的。
  1. 然后暴力枚举所给的序列应该属于的序列(每个数要么是上升序列中的数,要么是下降序列中的数)。对于每个序列采用上面的提到的贪心算法。
    (优化)
  2. 若dfs过程中,当前结果已经大于等于目前的最优解,直接return
    (剪枝)
  3. 然后对于为什么up数组是从大到小排列。因为这样排列后,只需顺序循环,找到比新来的数小的一个数后即为所求(寻找第一个小于新来的数)。若没有找到,咋增加一个上升序列,即将新来的数加到up数组末尾,up数组长度加一。down数组同理。

代码

const int N = 50 + 7, M = 1e6;
int up[N], down[N], a[N];
int ans, n;

//idx:原序列的第idx个数
//u,d:up,down数组的长度
void dfs(int idx, int u, int d)
{
	if (u + d >= ans) return;

	if (idx == n)
	{
		ans = min(ans, u + d);
		return;
	}
	//将第i个数加入到上升序列中
	int k = 0;
	while (k < u && up[k] >= a[idx]) k++;
	int t = up[k];//备份
	up[k] = a[idx];
	if (k < u) dfs(idx + 1, u, d);
	else dfs(idx + 1, u + 1, d);
	up[k] = t;//还原现场
	
	//将第i个数加入到下降序列中
	k = 0;
	while (k < d && down[k] <= a[idx]) k++;
	t = down[k];
	down[k] = a[idx];备份
	if (k < d) dfs(idx + 1, u, d);
	else dfs(idx + 1, u, d + 1);
	down[k] = t;//还原现场
}

int main()
{
	while (cin >> n, n)
	{
		for (int i = 0; i < n; i++)
			cin >> a[i];

		ans = n;
		dfs(0, 0, 0);

		cout << ans << endl;
	}


	return 0;
}
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

to cling

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值