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分
20 人评分
C语言程序设计教程(第三版)课后习题5.7 (C语言代码)浏览:747 |
川哥的吩咐 (C++代码)浏览:1076 |
小明A+B (C语言代码)浏览:1316 |
C语言考试练习题_排列 (C语言代码)浏览:767 |
C语言程序设计教程(第三版)课后习题7.2 (C语言代码)浏览:686 |
用筛法求之N内的素数。 (C语言代码)浏览:685 |
矩阵加法 (C语言代码)浏览:1768 |
剪刀石头布 (C语言代码)浏览:1519 |
C语言程序设计教程(第三版)课后习题5.5 (C语言代码)浏览:841 |
C语言程序设计教程(第三版)课后习题7.4 (C语言代码)浏览:522 |