【POJ3700】Missile Defence System——杨子曰题目

【POJ3700】Missile Defence System——杨子曰题目

To play against the threats of malicious countries nearby, Country R has updated their missile defence system. The new type system can bring down a series of missiles as long as they are coming in ascending order by altitude or descending order by altitude.

Given the heights of a sequence of coming missiles, the general wants to know how many sets of the new type systems are needed to bring down all of them.

Input
The input consists of several test cases. The first line of each test case contains an integer n(1 ≤ n ≤ 50). The next line contains n different integers indicating the heights.

Output
For each test case output a single line containing the number of systems needed.

Sample Input

5
3 5 2 4 1
0 

Sample Output

2

Hint
Two sets of systems are needed for the sample. One brings down 3, 4 and the other brings down 5, 2, 1.


偶尔也来讲一道水题吧!


一个草率的翻译,有一堆导弹飞了过来,你知道它们飞过来的顺序和高度,现在我们有一个很智障的导弹拦截系统,只能递增着打,或者只能递减着大(这是你可以决定的),问你最少要几个拦截系统才能拦截所有导弹


我们来暴搜
我们完全可以从前往后考虑,对于当前的导弹我们可以有一下几种选择:

  1. 接到一个递增的拦截系统后面
  2. 接到一个递减的拦截系统后面
  3. 新开一个递增的拦截系统
  4. 新开一个递减的拦截系统

然后你就发现复杂度炸了,So,我们还要对算法优化一下

我们来贪心地考虑一下这个问题,如果我们现在要把这个导弹接在一个递增的拦截系统后面,记录了这个拦截系统当前的高度,现在又很多的选择,真的要一一地去尝试吗?

当然不用,贪心一下就会发现显然是接在能接的拦截系统中高度最高的那一个后面最优

证明也很显然:我们既然要接,就一定会有一个拦截系统的高度变成当前这个导弹的高度,而由于我们考虑的是地怎的拦截系统,So,显然是当前高度矮的最有潜力,那对于当前导弹既然都可以接,那为什么要浪费一支潜力捏

而且我们还会发现:如果一个导弹可以接在已有的拦截系统后面,我们绝对不会新开一个拦截系统

递减的导弹系统一样滴

(我们以递增的拦截系统为例)
其实和上面的那个想法是一样的,我们把没开的拦截系统看成高度为0(如果是递减,就看作无穷大),于是你会发现接在一个以有的拦截系统后面,显然比接在高度为0的拦截系统后面要优(和上面同理)

综上所述,4个选择中,1,3只会选一个,2,4只会选一个,哦,变成二叉树了有没有,复杂度: O ( 2 n ) O(2^n) O(2n)

然后再加一个最优性剪枝,就是当前答案已经大于得到的答案时就不要往下走了

然后,我们就美滋滋地AC了!

注意一点:当前的递增导弹高度我们用一个数组存下,如果根据我们上面的方式进行搜索的话时可以保证这个数组递减的看,原因很简单,假设当前的数组是递减的,我们把这个数组从前往后扫,遇到第一个小于当前导弹高度的我们选择的对象,然后会把这个拦截系统的高度赋值成这个导弹,由于前面拦截系统的高度都大于这个导弹(否则就会接在它们后面了),So,我们依然保证了这个数组的递减性

递增的导弹也是一样滴

OK,完事


C++代码:

#include<cstdio>
#include<iostream>
#define inf 2000000000
using namespace std;

const int maxn=55;

int a[maxn],d[maxn],u[maxn],n,cnt1,cnt2,ans;//d是递减的拦截系统高度,cnt1是它的数量,u是递增的拦截系统高度,cnt2是它的数量

void dfs(int k){
	if (cnt1+cnt2>=ans) return;
	if (k==n+1){
		ans=min(ans,cnt1+cnt2);
		return;
	}
	for (int i=1;i<=cnt1;i++){
		if (u[i]<a[k]){
			int t=u[i];
			u[i]=a[k];
			dfs(k+1);
			u[i]=t;
			break;
		}
	}
	if (cnt1==0 || a[k]<=u[cnt1]){
		u[++cnt1]=a[k];
		dfs(k+1);
		cnt1--;
	}
	for (int i=1;i<=cnt2;i++){
		if (d[i]>a[k]){
			int t=d[i];
			d[i]=a[k];
			dfs(k+1);
			d[i]=t;
			break;
		}
	}
	if (cnt2==0 || a[k]>=d[cnt2]){
		d[++cnt2]=a[k];
		dfs(k+1);
		cnt2--;
	}
}

int main(){
	while(~scanf("%d",&n) && n){
		ans=inf,cnt1=cnt2=0;
		for (int i=1;i<=n;i++){
			scanf("%d",&a[i]);
		}
		dfs(1);
		printf("%d\n",ans);
	}
	return 0;
}

参考:
https://blog.csdn.net/qq_32944513/article/details/52806040

于HG机房

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值