LIS最長不下降(上升或持平)子序列 n * logn版
阿新 • • 發佈:2018-12-22
輸入多個數字,直到EOF,計算其LIS
我們暫且把n * logn演算法叫做“歪門邪道”,其機理如下:
“初始時dp[0] = s[0], 從i = 1時遍歷原數列, 將每個數與dp數列的末尾的數進行比較, 如果大於末尾的數, 就把s[i]放在dp數列的最後, 如果小於末尾的數,那麼就用s[i]替換掉dp中第一個比s[i]大的數。最後dp數列的長度就是LIS的長度,但是要注意dp中的數不是LIS的元素。”
嗯,之所以可以這樣做,是因為可以保證“歪門邪道”子序列末元素是LIS的元素(你寫個例子體會一下),必定存在那麼一個序列,以“歪門邪道”子序列末元素為末尾,且符合“不下降”規則…你說琢磨這個演算法的人他是咋想出來的…
#include <cstdio> #include <iostream> #include <cmath> #include <algorithm> #include <cstring> using namespace std; int main() { int s[25]; int dp[25]; memset(s, 0, sizeof(s)); memset(dp, 0, sizeof(dp)); int k = 0; int a; while(cin >> a) { s[k] = a; k++; // char b = getchar(); // if(b == '\n' ) // break; } dp[0] = s[0]; int len = 0; for(int i = 1; i < k; ++i) { if(s[i] >= dp[len]) dp[++len] = s[i]; else *lower_bound(dp, dp + len + 1, s[i]) = s[i]; if(s[i] <= dp[len]) dp[++len] = s[i]; // else // { // for(int j = 0; j < len + 1; ++j) // { // if(dp[j] < s[i]) // { // dp[j] = s[i]; // break; // } // } // } } // for(int i = 0; i < len + 1; ++i) // { // cout << dp[i] << " "; // } // cout << '\n'; cout << len + 1 << '\n'; return 0; }