The longest ascending subsequence (longest increasing subsquence) refers to a sequence that satisfies the oldest sequence a[j] of I < J < K and A[i] < A[k] < a[]. For example, 1 4 2 6 3 7 9, then "1,2,3,7,9" is its lis.
The general method of LIS is dynamic programming. There are two kinds of algorithms.
The first kind is better written, the Complexity O (n^2).
Set the original sequence to a[]. All subscripts start at 1 (i.e. [1,n]). Defines dp[i] as the length of the longest ascending subsequence ending with a[i]. It is easy to get the transfer equation: dp[i] = max{1, dp[j] + 1} and J < I. This can be updated:
Dp[i] = 1;
for (int j = 1; j < i; ++j) {
if (A[j] < a[i]) dp[i] = max (Dp[i], dp[j] + 1);
}
Select poj2533 here to illustrate the specific implementation.
#include <cstdio> #include <cstring> #include <algorithm>using namespace std;const int MAX = 1024;const int INF = 0xfffffff;int A[max];int dp[max];/*dp[i]: The length of the longest ascending subsequence ending with a[i] */inline int read () {char ch;while ((ch = getchar ( )) < ' 0 ' | | Ch > ' 9 '); int x = ch-' 0 '; while (ch = getchar ()) >= ' 0 ' && ch <= ' 9 ') {x = (x << 3) + (x << 1) + CH-' 0 ';} return x;} int main () {int n;while (~scanf ("%d", &n)) {for (int i = 1; I <= n; ++i) {A[i] = read ();} int ans = 0;for (int i = 1; I <= n; ++i) {Dp[i] = 1;for (int j = 1; j < i; ++j) {if (A[j] < A[i] && Dp[j] + 1 > Dp[i]) {dp[i] = Dp[j] + 1;}} if (Dp[i] > ans) ans = dp[i];} printf ("%d\n", ans);} return 0;}
In many cases, this solution does not achieve the complexity we need, because the actual situation is often millions of of the amount of data ... At this point we need to improve the above algorithm
Increasing the array d[],d[i] records all the minimum values in the a[] array that make the dp[j]=i. Maintenance d[] to satisfy the monotonicity (because it is the ascending sub-sequence, here is the monotonically increasing, if the descending sub-sequence expands to a monotonic reduction), and maintain a value maxlen record the longest position
Examples are as follows (subscript starting from 1):
For sequence a[] = {1,5,7,2,3,6,8}
Initialize d[] = INF. That is, any d[i] equals a large value to avoid affecting the answer. MaxLen = 0.
But d[0] =-inf, here's why.
First: Dp[1] = 1 (length 1), MaxLen = 1, d[1] = 1 (the minimum ending number of the longest ascending subsequence is 1 = a[1], equals 1), and the remaining d[i] remains unchanged (hereinafter). At this time d[] = {-inf, 1, INF, INF ... INF}
Second time: a[2] = 5 > D[maxlen]. Then dp[2] = maxlen + 1 = 2 (length 2), MaxLen = 2,d[2] = 5 (the smallest ending number with the longest ascending subsequence of 2 is 5). D[] = {-inf, 1, 5, INF,..., inf}
Third time: a[3] = 7 > D[maxlen], then dp[3] = maxlen + 1 = 3,maxlen = 3, d[3] = 7. At this time d[] = {-inf, 1, 5, 7, INF, INF, INF ...}
Fourth time: a[4] = 2 < D[maxlen], then from d[1] to D[maxlen, find the last number smaller than 2, find the number 1, the subscript is ind = 1 (d[1] = 1 ~), dp[4] = Dp[ind] + 1 = dp[1] + 1 = 2, MaxLen is 3 fixed, d[ind+1] = d[2] = 2. At this time d[] = {-inf, 1, 2, 7, INF, INF, INF ...}
Fifth time: A[5] = 3 < D[maxlen], then from d[1] to D[maxlen] Find the last number smaller than 3, find 2, subscript for ind = 2 (d[2] = 2 OH), dp[5] = Dp[ind] + 1 = dp[2] + 1 = 3, MaxL En is 3 fixed, d[ind+1] = d[3] = 3. At this time {-inf, 1, 2, 3, INF, INF, INF ...}
Sixth time: a[6] = 6 > D[maxlen], direct dp[6] = maxlen + 1 = 4, MaxLen = 4, d[4] = 6. At this time d[] = {-inf, 1, 2, 3, 6, INF, INF ...}
Seventh time: a[7] = 8 > D[maxlen], direct dp[7] = maxlen + 1 = 4, MaxLen = 5, d[5] = 8. At this time d[] = {-inf, 1, 2, 3, 6, 8, INF, INF ...}
This is the update process, why D[0] to initialize to a negative infinity (-inf) it? Because suppose a[] are all positive integers, previously recorded d[1] = 5. After a 1, obviously if d[0] is not very small, it is not good to find the so-called "than 1 small last number", no one is smaller than it!!!
But then again, find the last one smaller than it, update the value and go to update is the next number, then we might as well find the array {d[1] to d[i]} in the first than A[i] big number! Oh, that's it!
You're not going to get it now. We go through a lot of trouble to let d[] monotonically increment, and then deliberately select d[] in the update a[i] and greater than A[i] "junction point", in fact, is to use binary search, thus accelerating the entire algorithm! Binary search can achieve O (logn) complexity, so that we do not need to traverse all the 1<=j<i in the update, only need to update a point, complexity is not immediately lowered!
What's more, the last answer we get is MaxLen? What do you want to dp[] arrays for? Yes, if you only need the length of the longest ascending subsequence, this DP array is useless ... But I still habitually retained, in case of the use of ...
The following shows the implementation of poj2533:
#include <cstdio> #include <cstring> #include <algorithm>using namespace std;const int INF = 0XFFFFFFF; const int MAX = 1024;int dp[max];int a[max];int d[max];inline int Read () {char ch;while (ch = getchar ()) < ' 0 ' | | Ch & Gt ' 9 '); int x = ch-' 0 '; while (ch = getchar ()) >= ' 0 ' && ch <= ' 9 ') {x = (x << 3) + (x << 1) + ch -' 0 ';} return x;} int main () {int n;while (~scanf ("%d", &n)) {for (int i = 1; I <= n; ++i) {A[i] = read ();//SCANF ("%d", A + i);} Initialize Fill (d, D + n + 1, INF);d [0] =-inf;//-inf must be less than all a[i], otherwise it may affect the algorithm, the INF must be greater than all A[i] dp[0] = 0;//The reason for the initialization of int maxlen = 0;FO R (int i = 1; I <= n; ++i) {if (A[i] > D[maxlen]) {//At this point A[i] is added to the end to get a longer subsequence//must be executed at the first iteration here, we must guarantee a[1] > d[0]. This is also the reason for initializing the d[0]=-inf maxlen++;dp [i] = Maxlen;d[maxlen] = A[i];} else {int ind = Upper_bound (d, D + maxlen + 1, a[i])-D;//upper_bound find {d[0],.., D[maxlen]} first number greater than a[i], note subscript D[ind] = A[i];d P[i] = Dp[ind-1] + 1;//Imagine, here may find ind=1, then become dp[0]+1, so dp[0] initialized to 0}}printF ("%d\n", MaxLen);} return 0;}
toj4071:
#include <cstdio> #include <cstring> #include <algorithm>using namespace std;const int INF = 0XFFFFFF; const int MAX = 100007;int A[max], d[max];struct Node {int x, Y;bool operator< (const node& B) Const {return x = = b.x ? Y < b.y:x < b.x;}} Bird[max];inline int Read () {char ch;while (ch = getchar ()) < ' 0 ' | | ch > ' 9 '); int x = ch-' 0 '; while ((ch = getcha R ()) >= ' 0 ' && ch <= ' 9 ') {x = (x << 3) + (x << 1) + CH-' 0 ';} return x;} int main () {int T, n; T = Read (),//scanf ("%d", &t), while (t--) {n = read (),//scanf ("%d", &n), for (int i = 1; I <= n; ++i) {bird[i]. x = read (); bird[i].y = read ();//scanf ("%d%d", &bird[i].x, &BIRD[I].Y);} Sort (bird + 1, bird + n + 1); for (int i = 1; I <= n; ++i) {a[i] = bird[i].y;} Fill (d + 1, D + n + 1, INF), int maxlen = 0, ind;for (int i = 1; I <= n; ++i) {if (A[i] >= D[maxlen]) {++maxlen;d[max Len] = A[i];} else {ind = Upper_bound (d + 1, D + maxlen + 1, a[i])-d;d[ind] = A[i];}} printf ("%d\n", MaxLen);} return 0;}
"Longest ascending subsequence lis" O (n^2) and O (NLOGN) algorithm précis-writers