动态规划--最长单调递增子序列

问题:找出一个n个数的序列X中最长的单调递增子序列。

分析1:
这里描述一个O(n^2)的算法,令c[i]表示:在a[0->i]中,当以a[i]为单调递增子序列最后一个元素时,所得最长单调递增子序列的长度。所以,我们可以得到递推式:

 

代码:

#include #define MAXLENGTH 1000 using namespace std; /** * @brief Get the longest increasing subsequence. The time complexity is O(n^2). * * @param X[]: the sequence X. Index from 0 to n-1 * @param n: the length of X * @param c[]: c[i] means the longest increasing subsequence of X[0->i] when regard X[i] as the last element of increasing subsequence * @param line[]: the path of the longest increasing subsequence * * @return The longest increasing subsequence's length */ int LongestIncreasingSubsequence(int X[], int n, int c[], int line[]) { //path[i] point to the index of pre-element of i's element int path[MAXLENGTH]; for (int i = 0; i < n; ++i) { path[i] = i; } c[0] = 1; //construct c[][] for (int i = 1; i < n; ++i) { c[i] = 1; for (int j = 0; j < i; ++j) { if (X[i] >= X[j] && c[j] + 1 > c[i]) { c[i] = c[j] + 1; path[i] = j; } } } int max = 0; int end = -1; //get max and get the index of longest increasing subsequence's last element for (int i = 0; i < n; ++i) { if (c[i] > max) { max = c[i]; end = i; } } int i = 1; //get the longest increasing subsequence line[0] = X[end]; while (path[end] != end) { line[i++] = X[path[end]]; end = path[end]; } return max; } int main() { int n; int X[MAXLENGTH]; int c[MAXLENGTH]; int line[MAXLENGTH]; while (cin >> n, n != 0) { for (int i = 0; i < n; ++i) { cin >> X[i]; } int max = LongestIncreasingSubsequence(X, n, c, line); cout << "Longest Increasing Subsequence's Length: " << max << endl; for (int i = max - 1; i >= 0; --i) { cout << line[i]; } cout << endl; } }

 


 

 

分析2:
这里描述一个O(n*log(n))的算法,令c[i]代表:长度为i的单调递增子序列的最后一个元素在X中的位置。当一个新元素进来,生成新的长度为i的单调递增序列时,会覆盖掉c[i],从而保证c[i]尽量小。

 

代码:

 

#include #define MAXLENGTH 1000 using namespace std; /** * @brief Get the position of x in c[] * * @param c[]: the c[] which has the same meaning of LongestIncreasingSubsequence * @param len: the length of c[] * @param i: the i * @param X[]: the sequence X * * @return The i's position */ int GetPosition(int c[], int len, int i, int X[]) { int start = 1; int end = len; while (start <= end) { int mid = (start + end) / 2; if (X[c[mid]] <= X[i]) { start = mid + 1; } else { end = mid - 1; } } return start; } /** * @brief Get the longest increasing subsequence. The time complexity is O(n*log(n)). * * @param X[]: the sequence X. Index from 0 to n-1 * @param n: the length of X * @param c[]: c[i] means the last element's index in increasing subsequence whose length is i. If there are several subsequence whose length is i, c[i] should be the least one's index * @param path[]: record the elements' indexs in the longest increasing subsequence * * @return The longest increasing subsequence's length */ int LongestIncreasingSubsequence(int X[], int n, int c[], int path[]) { c[0] = -1; c[1] = 0; int line[MAXLENGTH]; //line[i] == -1 means that i is the first element's index int the increasing subsequence line[0] = c[0]; int len = 1; for (int i = 1; i < n; ++i) { int index = GetPosition(c, len, i, X); //c[index - 1] is the pre-element's index of element i line[i] = c[index - 1]; c[index] = i; if (index > len) { len = index; } } //get the path path[0] = c[len]; int i = 0; while (line[path[i]] != -1) { path[i + 1] = line[path[i]]; ++i; } return len; } int main() { int n; int X[MAXLENGTH]; int c[MAXLENGTH]; int path[MAXLENGTH]; while (cin >> n, n != 0) { for (int i = 0; i < n; ++i) { cin >> X[i]; } int max = LongestIncreasingSubsequence(X, n, c, path); cout << "Longest Increasing Subsequence's Length: " << max << endl; for (int i = max - 1; i >= 0; --i) { cout << X[path[i]]; } cout << endl; } }

你可能感兴趣的:(算法)