The longest increment subsequence problem in a column number to find some number satisfies any two number a[i] and a[j] If i<j must have a[i]<a[j] such longest subsequence is called the longest increment subsequence lis
There are two common methods to solve LIS problem, a time complexity n^n a time complexity Nlogn
Now, let's start with the n^n algorithm.
Set Dp[i] Indicates the length of the longest ascending sub-sequence ending with I the decomposition of the problem into the sequence of the maximum ascending subsequence of each of the most end-points, starting from the second item, and then finding the largest one is the answer. The state transfer equation is
Dp[i] = max{dp[j]+1}, 1<=j<i,a[j]<a[i].
Code Time Reference POJ2533
#include <iostream> #include <cstdio> #include <cstring>using namespace std;const int maxn = 1011;int an [Maxn];int dp[maxn];int Res;int Main () { int n; scanf ("%d", &n); for (int i = 1; I <= n; ++i) { scanf ("%d", &an[i]); } for (int i = 1; I <= n; ++i) { dp[i] = 1; for (int j = 1; j < i; ++j) { if (An[j] < An[i]) { dp[i] = max (Dp[i], dp[j] + 1); } } res = max (Dp[i], res); } printf ("%d\n", res); return 0;}
Let's take a look at another more efficient algorithm time complexity Nlogn
Suppose there is a sequence a[1..9] = 2 1 5 3 6 4 8 9 7 It can be seen that its LIS length is 5
We define a sequence DP and then let i = 1 to 9 examine the sequence
We'll use a variable len to record how long it's going to be.
First put a[1] into DP dp[1] = 2 that is, when there is only 11 digits 2, the minimum end of the LIS with length 1 is 2 then len=1
Then put a[2] in the order of the DP dp[1] = 1 that is, the smallest end of the LIS with a length of 1 is 1 a[1]=2 It's useless, it's easy to understand. Then Len=1
Then a[3] = 5 A[3]>dp[1] So dp[1+1]=dp[2]=a[3]=5 means that the minimum end of the LIS with a length of 2 is 5 this time dp[1..2] = 1 5 len=2
Again a[4] = 3 It just adds 1, 5 is placed in the position of 1 is obviously inappropriate because 1 is less than 3 of the length of the LIS minimum end should be 1 so it is easy to infer the length of the LIS minimum of 1 is 2 so you can eliminate 3 this time dp[1..2] = 5, 1 len = 3
Continue a[5] = 6 it after 3 because dp[2] = 3 and 6 after 3 so it is easy to infer dp[3] = 6 then dp[1..3] = 1, 3, 6, still easy to understand len = 3
6th A[6] = 4 You see it between 3 and 6 so we can replace 6 to get dp[3] = 4 dp[1..3] = 1, 3, 4 len continues to be equal to 3
7th A[7] = 8 It's much bigger than 4 mm so dp[4] = 8 Len becomes 4.
8th A[8] = 9 get dp[5] = 9 Len continues to grow to 5.
Last a[9] = 7 It is between dp[3] = 4 and dp[4] = 8 so we know the latest dp[4] =7 dp[1..5] = 1, 3, 4, 7, 9 len = 5
So we know that the LIS has a length of 5
Note that this 1,3,4,7,9 is not an LIS, it just stores the corresponding length of the LIS minimum end with this end we can insert the data one by one although the last a[9] = 7 update is not meaningful for this set of data but if there are two numbers 8 and 9 then you can update the 8 to A[5] 9 updated to a[6] The length of the LIS is 6
And then we should find something. Inserting data into a DP is ordered and replaced without moving--that is, we can use a binary search to optimize the insertion time of each number to O (logn) ~~~~~ so the time complexity of the algorithm is reduced to O (NLOGN)!
Attach the code implementation first HDU1950 more general wording
#include <iostream> #include <cstdio> #include <cstring>using namespace std;const int maxn = 40010;int AN[MAXN], DP[MAXN], Ans;int main () { int t; scanf ("%d", &t); while (t--) { int n; scanf ("%d", &n); for (int i = 1; I <= n; ++i) { scanf ("%d", &an[i]); } DP[1] = an[1]; ans = 1; for (int i = 2; I <= n; ++i) { int st = 1; int en = ans + 1; while (St < en) { int mi = (st+en)/2; if (An[i] <= Dp[mi]) { en = mi; } else{ st = mi + 1; } } Dp[en] = An[i]; if (en = = ans + 1) { ++ans; } } printf ("%d\n", ans); } return 0;}
The next thing you learned in the challenge is to use the lower_bound to achieve the two-point problem is still POJ2553
#include <iostream> #include <cstdio> #include <cstring> #include <algorithm>using namespace std;const int MAXN = 1011;const int inf = 0xffffff;int an[maxn];int dp[maxn];int main () { int n; scanf ("%d", &n); for (int i = 0; i < n; ++i) { scanf ("%d", &an[i]); } Fill (DP, dp+n, INF); for (int i = 0; i < n; ++i) { *lower_bound (DP, Dp+n, an[i]) = An[i]; } printf ("%d\n", Lower_bound (DP, DP+N, INF)-DP); return 0;}
Copyright NOTICE: This article for Bo Master original article, without Bo Master permission not reproduced.
Longest ascending subsequence lis solution (n^n && Nlogn)