首页 > 技术文章 > ybt1322 拦截导弹

Wild-Donkey 2020-02-17 20:14 原文

ybt1322 拦截导弹

【题目描述】

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

输入导弹依次飞来的高度(雷达给出的高度不大于30000的正整数)。计算要拦截所有导弹最小需要配备多少套这种导弹拦截系统。

【输入】

n颗依次飞来的高度(1≤n≤1000)。

【输出】

要拦截所有导弹最小配备的系统数k。

【输入样例】

389 207 155 300 299 170 158 65

【输出样例】

2

【提示】

输入:导弹高度:4 3 2

输出:导弹拦截系统 k = 1

【题解】

这道题的思路是令每套装置的价值最大化。

也就是说,避免让一个刚拦截了300m导弹的装置拦截50m的,而刚拦截60m导弹的装置就可以拦截它。

首先,第一发导弹是必须要用一套新的装置的。而第二发就有两种情况:比第一发高,只能再开一套;比第一发矮,使用第一套拦截。到了第i发导弹,就已经有u套装置。那么从小到大枚举装置能拦截的导弹高度,然后选择刚好能拦截i的最小的装置,就能最大限度减小浪费。如果所有装置都无法拦截,那么就新开一个装置来拦截。

关于维护升序排列的装置:由于只有所有装置都无法拦截才会新开装置,所以新装置能拦截的高度一定最高,放在最后是自然的。当由现有的j装置拦截了i导弹,装置j拦截高度更新,由于比j小的所有装置都无法拦截i,所以i的值一定大于1 - j-1,小于j - u的装置,所以j更新后位置不变。

综上所述,贪心策略正确。

代码:

#include<iostream>
#include<cstdio>
using namespace std;
int n, a[1005], f[1005], u=1;
int main() {
	int i = 1;
	while (cin >> a[i]) {//读入数据,直到输入结束为止
		i++;
	}
	f[1] = a[1];//使用新的装置拦截第一个导弹
	for (int j = 1; j <= i; j++) {//枚举每个导弹
		bool flag=0;//记录是否被拦截
		for (int k = 1; k <= u; k++) {//枚举用哪个装置
			if (f[k] >= a[j]) {//能拦截的第一套装置
				f[k] = a[j];//更新装置
				flag = 1;//打标记
				break;//停止枚举
			}
		}
		if (!(flag)) {//无法拦截,新建装置
			f[++u] = a[j];//放在最后
		}
	}
	cout << u << endl;//输出装置数量
	return 0;
}

推荐阅读