【杭电】[1257]最少拦截系统

文章字数:623

问题描述

问题分析

考虑若使炮弹命中最多,则炮弹命中导弹的导弹递减
所以需要发射LIS次,以为代表无法调整使其命中更多

n2一般dp算法:
对于每一个a[i]判断a[0i]能否把它更新成dp[j]+1
也就是看a[i]能否加在a[0
i]中的某个数之后
达到一个新的最大值

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
#include<stdio.h>
int a[30200],dp[30200];
int main() {
	int n;
	while(scanf("%d",&n)!=EOF) {
		for(int i=0; i<n; i++) {
			dp[i]=1;
			scanf("%d",&a[i]);
		}
		int res=0;
		for(int i=1; i<n; i++)
			for(int j=0; j<i; j++)
				if(a[i]>a[j]&&dp[i]<dp[j]+1) {
					dp[i]=dp[j]+1;
					if(res<dp[i])
						res=dp[i];
				}
		printf("%d\n",res);
	}
	return 0;
}

nlogn二分算法:

建一个数组保存取的数列的可能性
然后每判断到一个a[i]在s中找到一个s[k]<a[i]<s[k+1]的位置
然后用a[i]替换掉s[k+1]
也就是尽量用小的把使子序列相同的长度替换掉
这样可以保证后面的数比前面的数大的可能性提升
如果查找到s最后还没有a[i]<s[k+1]
则说明a[i]比目前s[k]的每一个数都大
这时候显然要把a[i]加到s的最后面

因为s中的数必然是单调递增的
所以在寻找位置的时候可以进行二分搜索优化时间
二分搜索的实现可以自己写函数
也可以调用C++中的lower_bound

自建函数:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
#include <stdio.h>
int inf=99999999;
int n,l;
int a[30200];
int s[30200];
int find(int m) {
	int la=0,lb=l;
	while(lb>=la) {
		int mid=(la+lb)>>1;
		if(s[mid]==m)
			return mid;
		else if(s[mid]>m)
			lb=mid-1;
		else
			la=mid+1;
	}
	return la;
}
int main() {
	while(scanf("%d",&n)!=EOF) {
		for(int i=1; i<=n; i++)
			scanf("%d",&a[i]);
		s[0]=-1;
		l=1;
		for(int i=1; i<=n; i++) {
			s[l]=inf;
			int t=find(a[i]);
			if(t==l)
				l++;
			s[t]=a[i];
		}
		printf("%d\n",l-1);
	}
	return 0;
}

运用C++函数:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
#include <stdio.h>
#include <algorithm>
using namespace std;
int inf=99999999;
int a[30200],s[30200];
int main() {
	int n;
	while(scanf("%d", &n)!=EOF) {
		for(int i=1; i<=n; i++)
			scanf("%d",&a[i]),s[i]=inf;
		int l=1;
		for(int i=1; i<=n; i++) {
			int k=lower_bound(s+1,s+n+1,a[i])-s;
			if(k==l)
				l++;
			s[k]=a[i];
		}
		printf("%d\n",l-1);
	}
	return 0;
}

该内容采用 CC BY-NC-SA 4.0 许可协议。

如果对您有帮助或存在意见建议,欢迎在下方评论交流。

加载中...