Longest Increasing Sequence: in a number sequence, find the longest subsequence (can be discontinuous), so that such subsequence is not decreasing (that is, non decreasing).

For example, sequence a = {1, 2, 3, -1, -2, 7, 9}, its longest non descending subsequence is {1, 2, 3, 7, 9} with length of 5, {1, 2, 3} and {- 2, 7, 9} are also non descending but not the longest.

Dynamic programming solution: dp[i] represents the length of the longest non descending subsequence ending with a[i]. So there are two possibilities for a[i]:

- There is a number a[j] (i.e. J < I) before a[i], which makes a[j] < = a[i]. That means that a[i] can form a new undiminished sequence after a[j]. At this time, whether dp[i] is to be updated depends on whether dp[j] + 1 is greater than dp[i]. (dp[j] + 1 indicates the length of LIS ending with a[j] plus a[i])
- All elements before a[i] are larger than it, so a[i] can only form a LIS by itself, so dp[i] = 1.

Therefore, the length of the longest non descending subsequence ending with a[i] is the larger of the above two results. State transfer mode:

dp[i]=max(1, dp[j]+1)(j=1,2,⋯ ,i−1 and a[j]<a[i])
dp[i] = max \left ( 1, \ dp[j] + 1 \right )
\left ( j = 1,2,\cdots,i-1\ and\ a[j]< a[i] \right )
dp[i]=max(1, dp[j]+1)(j=1,2,⋯,i−1 and a[j]<a[i])

Write the code:

#include <iostream> #include <vector> using namespace std; const int N = 110; int main() { int n, a[N], dp[N], ans = -1; cin >> n; for (int i = 0; i < n; i++) scanf("%d", &a[i]); for (int i = 0; i < n; i++) { dp[i] = 1; // The initial value is 1, i.e. take yourself as a sequence for (int j = 0; j < i; j++) { if (a[i] >= a[j] && dp[j] + 1 > dp[i]) { dp[i] = dp[j] + 1; } } ans = max(ans, dp[i]); } cout << ans; return 0; }

Input:

8 1 2 3 -9 3 9 0 11 1 2 3 3 9 11

Output:

6 // 1 2 3 3 9 11

The main problem here is to get the length of LIS, but it's really sad to be a good programmer if he doesn't output this sequence.

Solution: because there may be more than one sequence meeting the longest, declare vector < int > pre [n] to save all qualified sequences with precursor pointer in the way of adjacency table. Vector < int > dest stores the index of the end node of LIS.

After that, just use DFS to traverse the pre array:

void dfs(int u) { path.push_back(u); if (pre[u].size() == 0) { for (int i = path.size() - 1; i >= 0; i--) { printf("%d", a[path[i]]); if (i != 0) printf(" "); } printf("\n"); path.pop_back(); // 1 return; // 2 you can use these two sentences without adding them. In order to show that they have come to an end, return } for (auto it : pre[u]) dfs(it); path.pop_back(); // All the children of u have access to it. Remove U from the path array }

Complete implementation:

#include <iostream> #include <vector> using namespace std; const int N = 110; int n, a[N], dp[N], maxlen = -1, ansIndex = 0; vector<int> pre[N], path, ans; void dfs(int u) { path.push_back(u); if (pre[u].size() == 0) { for (int i = path.size() - 1; i >= 0; i--) { printf("%d", a[path[i]]); if (i != 0) printf(" "); } printf("\n"); path.pop_back(); // 1 return; // 2 you can use these two sentences without adding them. In order to show that they have come to an end, return } for (auto it : pre[u]) dfs(it); path.pop_back(); // All the children of u have access to it. Remove U from the path array } int main() { cin >> n; for (int i = 0; i < n; i++) scanf("%d", &a[i]); for (int i = 0; i < n; i++) { dp[i] = 1; for (int j = 0; j < i; j++) { if (a[i] >= a[j]) { if (dp[j] + 1 > dp[i]) { // If it is longer than the original LIS, the precursor of i will be cleared and j will be added dp[i] = dp[j] + 1; pre[i].clear(); pre[i].push_back(j); } else if (dp[j] + 1 == dp[i]) { // If it's the same length, then j can be added as an option pre[i].push_back(j); } } } if (dp[i] > maxlen) { maxlen = dp[i]; ans.clear(); ans.push_back(i); } else if (dp[i] == maxlen) { ans.push_back(i); } } for (auto it : ans) dfs(it); return 0; }

Input:

8 1 2 3 -9 3 9 0 11

Output: (there is only one substring satisfying LIS)

1 2 3 3 9 11