1. 直接说了,最多能拦截的导弹的高度是不能超过上一次的高度,所以容易能想到最多能拦截的导弹数量就是所给序列的最长不上升子序列长度(并不是最长下降子序列)。而要拦截所有导弹需要的系统数目就是所给序列的最长上升子序列的长度(也就是把最长上升子序列中每一个数字分到不同的组里面即可),另外需要注意这个必须是最长上升子序列哈~。
例如样例:389 207 155 300 299 170 158 65 111
能拦截最多的导弹是6颗:389 300 299 170 158 65
需要2台机器才能够拦截所有导弹:
第一台:389 300 299 170 258 65
第二台:207 155 111
2. 综上自己可以具体的画一画理解一下,下面具体说一下动态规划求最长上升子序列的求法:
已知序列f[N];
设dp[i]表示以f[i]结尾的最上上升子序列的长度,那么有如下状态转移方程:
dp[i] = max{dp[i], dp[j] + 1}, 0 <= j < i且f[j] < f[i];
根据上述推理过程两层for循环就可以求出最终结果。
最长不上生子序列的求解方法和最长上升子序列的方法是相同的只需将条件中的 <
改为 >= 即可;状态转移方程如下:
dp[i] = max{dp[i], dp[j] + 1}, 0 <= j < i且f[j] >= f[i];
3. 注意:dp过程中并不是最终结果就是最优值,需要再dp过程中记录最优值。
4. 代码如下:
#include <bits/stdc++.h> using namespace std; const int N = 3e4 + 9; int dp1[N], dp2[N], f[N]; int main() { int idx = 0, ans = 0, cnt = 0; while(~scanf("%d", &f[idx])) idx++; // 遇到文件尾自动结束 for(int i = 0; i < idx; ++i) { dp1[i] = dp2[i] = 1; for(int j = 0; j < i; ++j) { if(f[i] <= f[j]) { // 最长不上升子序列 if(dp1[i] < dp1[j] + 1 ) dp1[i] = dp1[j] + 1; } else { // 最长上升子序列 if(dp2[i] < dp2[j] + 1 ) dp2[i] = dp2[j] + 1; } } if(ans < dp1[i]) ans = dp1[i]; if(cnt < dp2[i]) cnt = dp2[i]; } printf("%d\n%d\n", ans, cnt); return 0; }
如有错误,谢谢指出,纯手打…………
0.0分
3 人评分
C语言网提供由在职研发工程师或ACM蓝桥杯竞赛优秀选手录制的视频教程,并配有习题和答疑,点击了解:
一点编程也不会写的:零基础C语言学练课程
解决困扰你多年的C语言疑难杂症特性的C语言进阶课程
从零到写出一个爬虫的Python编程课程
只会语法写不出代码?手把手带你写100个编程真题的编程百练课程
信息学奥赛或C++选手的 必学C++课程
蓝桥杯ACM、信息学奥赛的必学课程:算法竞赛课入门课程
手把手讲解近五年真题的蓝桥杯辅导课程
发表评论 取消回复