LIS, LCS algorithm prefix
Longest Ascender Sequence I
Dynamic Programming\(O(n^2)\)
Partition the set by the second to last number.
- State representation
- Set Definition
All ascending subsequences ending in number \(i\) - attribute
Max
- Set Definition
- Set Partition
- Currently there are only \(i\) numbers, \(f[i] = 1\);
- There are cases smaller than the current number, \(f[i] = max(f[i], f[j]+1),j\in(0,1,2,3\ldots,i-1)\)
Code
for (int i = 1; i <= n; ++i) { f[i] = 1; for (int j = 0; j < i; ++j) if (w[j] < w[i]) f[i] = max(f[i], f[j]+1); } int res = -1; for (int i = 1; i <= n; ++i) res = max(res, f[i]);
Longest Rising Subsequence II
Greed+Binary\(n\log_{2}^{n}\)
First go up the code for Big Man 233
vector<int>stk;//Analog Stack stk.push_back(arr[0]); for (int i = 1; i < n; ++i) { if (arr[i] > stk.back()) stk.push_back(arr[i]); else *lower_bound(stk.begin(), stk.end(), arr[i]) = arr[i]; } cout << stk.size() << endl;
The definition of the stack here is not really the longest ascending subsequence, but the lowest end element in the ascending subsequence of length \(i\). For an increasing subsequence, we want the smaller the end element, the better it will be, so that we can have a wider range of subsequent connectable numbers and a longer length.
Greedy Ideas
- Nature
As the length of the increasing subsequence increases, the minimum value of the end element must also increase strictly monotonically. - Prove
Assuming the length of two increasing subsequences is \ (x,y and x < y\), the end elements of both subsequences are the same. So in an increasing subsequence of length \(y\), the end element must be less than the second-to-last element, then the second-to-last element is also less than the end element in the increasing subsequence of length \(x\), which is inconsistent with the nature, because we store the minimum end element in the ascending subsequence of length \(i\).
extend
Kidd's gliding wings
Problem: Find the longest ascending and descending subsequences.
thinking
Solving the longest ascending subsequence is from left to right. Now the longest descending subsequence is required. A longest ascending subsequence can be found in reverse order. The longest ascending subsequence from right to left is the longest descending subsequence from left to right.
Code
w[n + 1] = 0; for (int i = n; i; -- i) { for (int j = n + 1; j > i; -- j) { if (w[i] > w[j]) f_dw[i] = max(f_dw[i], f_dw[j] + 1); } }
Maximum ascending subsequence sum
thinking
Change the set property from the maximum of length to the maximum of the sum of the subsequences.
Code
int res = -1; for (int i = 1; i <= n; ++i) { f[i] = a[i]; for (int j = 1; j < i; ++j) if (a[i] > a[j]) f[i] = max(f[i], f[j] + a[i]); res = max(res, f[i]); }
Mountaineering
Problem: Find the maximum of the sum of the lengths of the longest ascending and descending subsequences on both sides at the inflection point of \(i\).
thinking
Based on Kidd's gliding wing problem, make the longest ascending subsequence once on both sides, and then sum the two at the \(i\) turning point to get the maximum value.
Code
The subsequence solving process is no longer repeated twice here.
for (int i = 1; i <= n; ++i) res = max(res, f[i] + f2[i] - 1); // Subtract 1 because they are duplicated at i.
Chorus Formation
Problem: Find the minimum of the total number minus the sum of the lengths of the longest ascending and descending subsequences on both sides at the \(i) inflection point.
thinking
As with mountaining problems, the longest ascending and descending subsequences of each point are preprocessed, and the sum of the two subsequences is the maximum. The code is no longer repeated.
Intercept Missile
Problem: Find out how many non-ascending subsequences the length of the longest ascending subsequence can be divided into at least one original sequence.
problem analysis
It is no longer repeated for the longest ascending subsequence. The difficulty of this problem is that the original sequence can be completely covered by at least a few subsequences which are not ascending.
Thoughts (based on greed)
Defines an array \(q\), the length of which is the number of ascending subsequences, in which the last number of each ascending subsequence is stored.
Traversing through the original sequence, for each number in the original sequence, we make the following judgment
- If none of the numbers in the \(q\) array is larger than that, create a new group to store the number.
- If 1 is unsuccessful, find the minimum value greater than or equal to in the \(q\) array and replace it.
Relevant Proof
- Array\(q\) is a monotonically increasing sequence
Consider the array \(q\) as a set, with an initial state of empty set and a numeric size and length of 0. When we traverse each element in the original array \(x\), there must be an unequal relationship \(c>x>=a>=b\), replace \(x\) with \(a\) elements in \(q\), and monotonicity does not change.
In addition, each step will look for a smaller tail in the set to replace it, and if there is no smaller number, a new maximum element will be added, so the array\(q\) increases with the subscript, and the stored value increases, so it monotonically increases the sequence. - Correctness of Greed
Adjustment method, specific proof separate solution, will not be expanded here.
Code
int res = 0, cnt = 0; for (int i = 0; i < n; i++) { f[i] = 1; for (int j = 0; j < i; j++) if (w[i] <= w[j]) f[i] = max(f[i], f[j] + 1); res = max(res, f[i]); int k = 0; while (k < cnt && q[k] < w[i]) k++; if (k == cnt) q[cnt++] = w[i]; else q[k] = w[i]; }
Missile Defense System
Question: At least how many ascending and descending subsequences are required to fully cover the original array.
Differential Intercept Missile
The subsequences solved by interception missiles are monotonic and not ascending. In this problem, both ascending and non-ascending subsequences are combined to find the minimum of the total number of subsequences.
problem analysis
For each number \(x\) in the original sequence, there are two possibilities that a new subsequence will be generated, either in an ascending subsequence or in a non-ascending subsequence. The generation of this subsequence will affect the two possibilities of the subsequent number, and will continue to affect the answer and result in new results.
Consider whether there is a way to predict the impact of inserting a subsequence of \(x\) on the results without knowing the prophet? The answer is No. Then we have to solve the possibility of all the subsequent results it produces by violence, and at the end we get a minimum of all the possibilities, that is, by using violence search.
algorithm
Now that you're using storm search, a simple analysis of time complexity yields a time complexity of \(O(n2^n)\) that needs to be pruned. This topic can be optimized by referring to the greedy nature of the motif LIS II.
optimization
Two arrays can be used to store the end number of each ascending subsequence and the end value of each non-ascending subsequence, so that we can quickly locate which subsequence we need to insert behind, and the greedy idea that the two arrays must be monotonic, the first one that meets the criteria will exit the loop. Binary optimization can also be used for further optimization.
How to Search
Because the scope of this question n is small, you can use iteration to deepen the search to solve the problem, or you can record a global minimum and keep updating it.
Code
The yls code is pasted here directly.
int n; int h[N]; int up[N], down[N]; bool dfs(int depth, int u, int su, int sd) { // If the number of ascending sequences + descending sequences > the total number is the upper limit, then backtracking if (su + sd > depth) return false; if (u == n) return true; // Enumerate cases placed in ascending subsequence bool flag = false; for (int i = 1; i <= su; i ++ ) if (up[i] < h[u]) { int t = up[i]; up[i] = h[u]; if (dfs(depth, u + 1, su, sd)) return true; up[i] = t; flag = true; break; } if (!flag) { up[su + 1] = h[u]; if (dfs(depth, u + 1, su + 1, sd)) return true; } // Enumerate the cases placed in the descending subsequence flag = false; for (int i = 1; i <= sd; i ++ ) if (down[i] > h[u]) { int t = down[i]; down[i] = h[u]; if (dfs(depth, u + 1, su, sd)) return true; down[i] = t; flag = true; break; } if (!flag) { down[sd + 1] = h[u]; if (dfs(depth, u + 1, su, sd + 1)) return true; } return false; } int main() { while (cin >> n, n) { for (int i = 0; i < n; i ++ ) cin >> h[i]; int depth = 0; while (!dfs(depth, 0, 0, 0)) depth ++ ; // Iteration Deepening Search cout << depth << endl; } return 0; }
Longest Common Rising Subsequence
State representation f[i][j]
- aggregate
Set of all common ascending subsequences that occur in (A[1-i]\) and (B[1-j]\) and end with \(B[j]\) - attribute
max
State calculation
- \(A[i]\) is not included in a common subsequence\[f[i][j] = f[i-1][j] \]
- \(A[i]\) is contained in a common subsequence
There must be \(A[i]=B[j]\) first, because \(A[i]\) must be last if it is included.
Secondly, the set is divided into \(1- (i-1)\) segments according to the second last number, and the solution is obtained. The transfer equation is
Code
Go directly to yls code.
for (int i = 1; i <= n; i ++ ) { int maxv = 1; for (int j = 1; j <= n; j ++ ) { f[i][j] = f[i - 1][j]; if (a[i] == b[j]) f[i][j] = max(f[i][j], maxv); if (a[i] > b[j]) maxv = max(maxv, f[i - 1][j] + 1); } } int res = 0; for (int i = 1; i <= n; i ++ ) res = max(res, f[n][i]);