定义:在一个没有排好序的数组中,找最长的单调递减或单调递增的序列。
解题思路:通过动态规划解题。假设从0--(i - 1)已经构成了长度为s的递减序列,且这些序列中的末尾值中的最大值为t;
1、如果a[i] < t,则假如到这个序列中去,长度变为s + 1。对应的末尾值变为a[i]。
2、如果a[i] == t, 则说明从0 - i 的最长序列长度为s。
3、如果a[i] > t,a[i]不一定能成为最长序列的末尾值。此时取绝于长度为s - 1的序列的末尾最大值是max。如果max > a[i],则他可以成为长度为s的递减序列。如果max < a[i], 继续往前推, 直到a[i]小于某个末尾的最大值,此时长度为k。那么a[i]是0-i中长度为k + 1的递减序列的最大值。
两个实例:
1.拦截导弹
题目描述:
某国为了防御敌国的导弹袭击,开发出一种导弹拦截系统。但是这种导弹拦截系统有一个缺陷:虽然它的第一发炮弹能够到达任意的高度,但是以后每一发炮弹都不能高于前一发的高度。某天,雷达捕捉到敌国的导弹来袭,并观测到导弹依次飞来的高度,请计算这套系统最多能拦截多少导弹。拦截来袭导弹时,必须按来袭导弹袭击的时间顺序,不允许先拦截后面的导弹,再拦截前面的导弹。
参考代码:
#include<iostream> #include<vector> #include<string.h> #include<algorithm> // 直接使用max函数 using namespace std; int a[30]; int main(){ int k; while(cin >> k){ for(int i = 0; i < k; i ++){// 输入序列 cin >> a[i]; } vector<int> dp(k, 1);// 初始化 dp[0] = 1; int maxVal = 1; for(int i = 1; i < k; i ++){ for(int j = i; j > 0; j --){// 看前面的数是否比我(a[i])大 if(a[i - j] >= a[i]){// 不同于递减的情况,是不高于 dp[i] = max(dp[i], dp[i - j] + 1); } } if(maxVal < dp[i]){ maxVal = dp[i]; } } // for(int i = 0; i < k; i ++){// 将每个序列长度输出 // cout << dp[i] << " "; // } // cout << endl; cout << maxVal << endl; } return 0; }
2.最大上升序列和
一个数的序列bi,当b1 < b2 < ... < bS的时候,我们称这个序列是上升的。对于给定的一个序列(a1, a2, ...,aN),我们可以得到一些上升的子序列(ai1, ai2, ..., aiK),这里1 <= i1 < i2 < ... < iK <= N。比如,对于序列(1, 7, 3, 5, 9, 4, 8),有它的一些上升子序列,如(1, 7), (3, 4, 8)等等。这些子序列中序列和最大为18,为子序列(1, 3, 5, 9)的和. 你的任务,就是对于给定的序列,求出最大上升子序列和。注意,最长的上升子序列的和不一定是最大的,比如序列(100, 1, 2, 3)的最大上升子序列和为100,而最长上升子序列为(1, 2, 3)。
参考代码:
这题和上题的解题思路很类似,有些许的改动处,我在代码中已经给出了注释。
#include<iostream> #include<vector> #include<string.h> #include<algorithm> // 直接使用max函数 using namespace std; int a[1001], dp[1001]; int main(){ int n; while(cin >> n){ for(int i = 0; i < n; i ++){// 输入序列 cin >> a[i]; } memset(dp, 0, sizeof(dp));// 初始化 int maxVal = a[0]; for(int i = 0; i < n; i ++){ dp[i] = a[i];// dp[i]的初值就是a[i],找到比它小的相加即可 for(int j = 0; j < i; j ++){// 找前面的数是否都比我小 if(a[j] < a[i]){ // dp[j]就是之前的各值得和,加上这次得标志位a[i] dp[i] = max(dp[i], dp[j] + a[i]); } } if(maxVal < dp[i]){// 每次比较一下,最后保留一个最大值,也可以做完之后,遍历dp数组 maxVal = dp[i]; } } // for(int i = 0; i < n; i ++){// 输出每组和的结果 // cout << dp[i] << " "; // } // cout << endl; cout << maxVal << endl; } return 0; }
以上是这篇的主要内容。欢迎您提出宝贵的意见,让我们一同进步。谢谢!