问题背景 |
动态规划入门-第18题 |
试题描述 |
某国为了防御敌国的导弹袭击,发明出一种导弹拦截系统。但是这种导弹拦截系统有一个缺陷:虽然它的第一发炮弹能够到达任意的高度,但是以后每一发炮弹都不能高于前一发的高度。 某天,雷达捕捉到敌国的导弹来袭。由于该系统还在试用阶段,所以只有一套系统,因此有可能不能拦截所有的导弹。 现在,要你计算出这套系统最多能拦截多少枚导弹,并且如果要拦截所有导弹的话,最少要配备多少套这种导弹拦截系统。 |
输入格式 |
输入数据为两行。 第一行为一个整数,表示导弹的数目N。 第二行为N个整数,表示第i枚导弹飞来的高度Hi。 |
输出格式 |
输出只有一行。 这一行只有两个整数,即这套系统最多能拦截的导弹数和要拦截所有导弹最少要配备这种导弹拦截系统的套数。 |
输入示例 |
8 389 207 155 300 299 170 158 65 |
输出示例 |
6 2 |
注释说明 |
1≤N≤1000,1≤Hi≤30000。 |
【分析】
先做第一问,LIS一遍即可。
再看第二问,即求至少有多少个最长不上升子序列,每次从最高的点开始找就可以啦。
依然dp入门,很水。
【代码】
1 #include <bits/stdc++.h> 2 using namespace std; 3 4 int ans, n, a[1020], dp[1020], fa[1020]; 5 bool vis[1020]; 6 7 void init() 8 { 9 cin >> n; 10 for (int i=1;i<=n;++i) 11 cin >> a[i]; 12 } 13 14 bool check() { 15 for (int i=1;i<=n;++i) 16 if (!vis[i]) 17 return false; 18 return true; 19 } 20 21 void sovle1() 22 { 23 memset(dp, 0, sizeof(dp)); 24 ans=0; 25 for (int i=1;i<=n;++i) { 26 dp[i]=1; 27 for (int j=1;j<i;++j) 28 if (a[i]<=a[j]) 29 dp[i]=max(dp[i], dp[j]+1); 30 ans=max(ans, dp[i]); 31 } 32 cout << ans; 33 return; 34 } 35 36 void sovle(int x) { 37 if (fa[x]) 38 vis[fa[x]]=true; 39 else 40 return; 41 sovle(fa[x]); 42 } 43 44 void sovle2() { 45 for (int k=1;;++k) { 46 memset(dp, 0, sizeof(dp)); 47 memset(fa, 0, sizeof(fa)); 48 if (check()) { 49 cout << k-1 << endl; 50 exit(0); 51 } 52 int maxx=0, maxi=0, t=0, ti=0; 53 for (int i=1;i<=n;++i) { 54 if (!vis[i] && maxx<a[i]) 55 maxx=a[i], maxi=i; 56 } 57 for (int i=maxi;i<=n;++i) { 58 dp[i]=1; 59 for (int j=maxi;j<i;++j) { 60 if (!vis[i] && !vis[j] && a[i]<=a[j] && dp[j]+1>dp[i]) { 61 fa[i]=j, dp[i]=dp[j]+1; 62 } 63 } 64 if (dp[i]>t) 65 t=dp[i], ti=i; 66 } 67 vis[ti]=true; 68 sovle(ti); 69 } 70 } 71 72 int main() 73 { 74 init(); 75 sovle1(); 76 cout << " "; 77 sovle2(); 78 }
时间: 2024-10-08 09:30:28