1010. 拦截导弹,贪心(附贪心证明),dp

1010. 拦截导弹 - AcWing题库

某国为了防御敌国的导弹袭击,发展出一种导弹拦截系统。

但是这种导弹拦截系统有一个缺陷:虽然它的第一发炮弹能够到达任意的高度,但是以后每一发炮弹都不能高于前一发的高度。

某天,雷达捕捉到敌国的导弹来袭。

由于该系统还在试用阶段,所以只有一套系统,因此有可能不能拦截所有的导弹。

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

输入格式

共一行,输入导弹依次飞来的高度。

输出格式

第一行包含一个整数,表示最多能拦截的导弹数。

第二行包含一个整数,表示要拦截所有导弹最少要配备的系统数。

数据范围

雷达给出的高度数据是不大于 3000030000 的正整数,导弹数不超过 10001000。

输入样例:
389 207 155 300 299 170 158 65
输出样例:
6
2

 解析:


贪心猜想:
从前往后扫描每个数,对于每个数:
情况1:如果现存的下降子序列的结尾的数都小于当前的数,则创建新的子序列
情况2:将当前数放到子序列结尾数最小的大于等于它的子序列后面

贪心猜想的证明:
令 A = 贪心的结果,B = 最优解;
则只需证明 A<=B 且 B<=A;(常用贪心证明方式)

B<=A:
这显然成立,因为 B 为最优解
A<=B:
使用调整法:
最优情况下放置的位置非当前 X 放置的位置,则最有情况下放置的位置的结尾数一定小于当前 X 放置的位置,则我们根据上述贪心的方法一定可以将 X 放置到最优情况的位置,且不增加下降子序列的个数
所以:A<=B
综上所述,此贪心方法一定可以得到最优解

我们发现这个方法是最长上升子序列问题 的贪心解法
896. 最长上升子序列 II - AcWing题库

 这道题的另一种就是直接使用Dilworth 定理

 dp1,ACM暑期培训-CSDN博客

这里我们实际上是将这个定理给证明了;

#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
using namespace std;
typedef long long LL;
const int N = 1e3 + 5;
int n;
int q[N], f[N],g[N];

int main() {
	while (cin >> q[n])n++;
	int ans = 0;
	for (int i = 1; i <= n; i++) {
		f[i] = 1;
		for (int j = 1; j < i; j++) {
			if (q[i] <= q[j])
				f[i] = max(f[i], f[j] + 1);
		}
		ans = max(ans, f[i]);
	}
	cout<= cnt)cnt++;
	}
	cout << cnt << endl;
	return 0;
}

你可能感兴趣的:(贪心,#,线性dp,算法,贪心算法,动态规划)