1012 [NOIP1999]拦截导弹 最长单调不增子序列 伪数据

链接:https://ac.nowcoder.com/acm/problem/16810
来源:牛客网

题目描述

某国为了防御敌国的导弹袭击,发展出一种导弹拦截系统。但是这种导弹拦截系统有一个缺陷:虽然它的第一发炮弹能够到达任意的高度,但是以后每一发炮弹都不能高于前一发的高度。某天,雷达捕捉到敌国的导弹来袭。由于该系统还在试用阶段,所以只有一套系统,因此有可能不能拦截所有的导弹。
输入导弹依次飞来的高度(雷达给出的高度数据是不大于30000的正整数),计算这套系统最多能拦截多少导弹,如果要拦截所有导弹最少要配备多少套这种导弹拦截系统。

输入描述:

1行,若干个整数(个数≤100000)

输出描述:

2行,每行一个整数,第一个数字表示这套系统最多能拦截多少导弹,第二个数字表示如果要拦截所有导弹最少要配备多少套这种导弹拦截系统。
示例1

输入

复制
389 207 155 300 299 170 158 65

输出

复制
6
2

分析

这道题是个伪1w,总共十个炸弹都没有,所以最长单调递增子序列就可以做了。。

此题有两个问题,第一求这套系统最多能拦截多少导弹,第二个求如果要拦截所有导弹最少要配备多少套这种导弹拦截系统。

第一个问题即为求最长下降子序列,不多阐述。

对于第二个问题我是用贪心求解的。
对于每一个处在i位置的导弹,它可以和(从1到i-1位置且还没有被击落的)任一大于等于其高度的导弹共在一套装置(意思即为无需添置新的装置),在此想既然是选一个符合要求的导弹共处一套装置,则选对于之后的更有利的导弹(即为选比位置i导弹高度高的所有导弹中高度最小的那个,可以好好思考一下为何如此选)。(易错点)

 

 

#include<bits/stdc++.h>
#define dbb(i,a,b) cout<<#i<<':'<<i<<' '<<#a<<':'<<a<<' '<<#b<<':'<<b<<endl;

using namespace std;
const int N = 1e5+10;
int n;
int f[N],flag[N],a[N],cnt,g[N],res;

void solve() {
memset(f,0,sizeof f);
for(int i = 1;i<=n;i++) {
f[i] = 1;
for(int j = 1;j<i;j++) {
if(a[j] >= a[i] && !flag[j] && !flag[i]) {
if(f[i] < f[j] + 1) {
f[i] = f[j] + 1;
g[i] = j;
}
}
}
}
// for(int i = 1;i<=n;i++) cout<<f[i]<<' ';
// cout<<endl;
int t,ans = 1;
for(int i = 1;i<=n;i++) {
if(f[i] > ans && !flag[i]) {
ans = f[i];
t = i;
}
}
if(!cnt) cout << ans<<endl;
cnt += ans;
res ++ ;
for(int i = 0;i<ans;i++) {
flag[t] = 1;
t = g[t];
}
}

int main() {
n = 1;
while(cin>>a[n])n ++;
n -- ;
while(cnt != n) {
solve();
}
cout<<res<<endl;
}

posted @ 2022-07-06 13:46  er007  阅读(26)  评论(0编辑  收藏  举报