# [algorithm] dynamic programming - longest non descending subsequence (LIS)

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]:

1. 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])
2. 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

Published 25 original articles, praised 0, visited 48

Tags: Programming

Posted on Fri, 14 Feb 2020 02:25:57 -0500 by justinwhite93