CODEVS 1576 最長嚴格上升子序列
阿新 • • 發佈:2019-02-15
題意
找出一個序列中上升子序列
例如 2 1 5 3 6 4 8 9 7
上升子序列:1 5 6 8 9 或者 1 3 4 8 9 但是子序列長度都是5
思路
有兩種想法:一是動歸,一是每次從前往後找第一大並且替換。這樣做的能得到最長序列的次數,但是無法知道最長序列是什麼。
程式碼
動歸
#include<iostream>
using std::cin;
using std::cout;
using std::endl;
int size; //陣列長度
int a[5001]; //原陣列
int dp[5001]; //序列長度陣列
int main(int argc,char *argv[])
{
cin >> size;
for(int i = 0;i < size;i++) {
cin >> a[i];
dp[i] = 1;
}
for(int i = 0;i < size;i++) {
for(int j = 0;j < i+1;j++) {
if((a[i] > a[j]) && dp[j]+1 > dp[i]) {
dp[i] = dp[j]+1 ; //動歸的遞推式
}
}
}
int max = 1;
for(int i = 0;i < size;i++) { //找出最大值
if(dp[i] > max) {
max = dp[i];
}
}
cout << max << endl;
return 0;
}
O(n^2)
#include<iostream>
using std::cin;
using std::cout;
using std ::endl;
int size; //a陣列大小
int a[5001]; //原陣列
int dp[5001]; //和子序列個數相同的陣列,但是元素不一定是子序列
int len = 0; //dp陣列長度
int flag = 0;
int main(int argc,char *argv[])
{
cin >> size;
for(int i = 0;i < size;i++) {
cin >> a[i];
}
dp[0] = a[0];
len++;
for(int i = 0;i < size;i++) {
flag = 0;
for(int j = 0;j < len;j++) {
if(a[i] <= dp[j]) {
dp[j] = a[i];
flag = 1;
break;
}
}
if(flag == 0) {
dp[len] = a[i];
len++;
}
}
cout << len << endl;
return 0;
}
二分優化方法二,為O(nlog(n))
#include<iostream>
using std::cin;
using std::cout;
using std::endl;
int size; //a陣列長度
int a[100];
int dp[100];
int len = 0;
int max = 0; //dp陣列長度,也就是最大字串的長度。
void findFirstBig(int begin,int end,int find) //二分查詢dp陣列中第一個比find大的元素
{
while(begin <= end) {
int mid = (begin+end)/2;
if(dp[mid] == find) {
return;
}
if(dp[mid] < find) begin = mid+1;
if(dp[mid] > find) end = mid-1;
}
len = begin;
}
int main(int argc,char *argv[])
{
cin >> size;
for(int i = 0;i < size;i++) {
cin >> a[i];
}
dp[0] = a[0];
for(int i = 0;i < size;i++) {
if(a[i] > dp[max]) { //如果下一個元素比dp陣列中最大的還大
max++;
dp[max] = a[i];
}
else {
findFirstBig(0,max,a[i]);
dp[len] = a[i];
}
}
cout << max+1 << endl;
return 0;
}