求乙個正整數序列的最長單調自增子序列,子串行不要求是連續的。例如
input:5
5 2 4 3 1
output:2
確定狀態轉移方程,設f[i]是以a[i]為結尾的最大值的子串行的長度,那麼\[\max \ \]的最大值就是要的結果。
所以轉移方程為:
\[f(i) = \max \ > \} + 1\]
所以**可以為:
void main(void); int dist[6];
int path[6];
int num = 6;
int i = 0;
for(i = 0; i < 6; i++)
for(i = 0; i < num; i++)
//if
}//for
dist[i] = temp + 1;
path[i] = index;
}//for
//找到最大的那個值
int max = 0;
int maxindex = -1;
for(int m = 0; m < num; m++)
}//for
printf("最長單曾子串行的長度是%d.\n", max);
while(path[maxindex] != -1)
//while
printf("%d\n", arr[maxindex]);
}
很顯然時間複雜度是o(n*n),那麼有沒有更快的演算法呢?按照正常的思路更快的複雜度應該就是o(n*logn),那麼就要涉及到二分了。
建立乙個輔助陣列c[n],c[i]=j儲存的是子串行長度為i的序列最後乙個值j(實際上子串行長度為i的子串行有多個,要的是子串行最後乙個值最小的)。
這時要遍歷要處理的陣列arr[n]。
for(i=0;i請看一下上面的例子實際執行的情況:c陣列變化的情況-15-1
2-124
-112-1
14-11
3
arr陣列遍歷是從前往後的,處理arr[i-1]時arr[i]以及後面的值肯定還沒有處理,前面的值都處理過了,看c陣列,每個arr陣列中的值和c陣列中值進行比較,找到合適的位置插入(若插入到c陣列的末尾,那麼就屬於最長遞增子串行長度加1,實際上c陣列的長度就是最後的最長單調遞增子串行的長度。),否則這就替換掉了c陣列中原來位置儲存的值,這種替換是有意義的,主要是為了後來的arr陣列中的值計算dist用(dist[i]中儲存的是以arr[i]為最後乙個元素的最長單調遞增子串行。)好處是若arr[i]
下面給出完整的演算法
#include #define max 100void fill(int a, int len);
int find(int a, int clastindex, int x);
int main()
; int dist[max] = ;
int c[max];
int num; //原始數字序列的長度
int i = 0;
freopen("in.txt", "r", stdin);
freopen("out.txt", "w", stdout);
printf("讀取數字序列長度...\n");
scanf("%d", &num);
printf("讀取數字序列...\n");
for(i = 0; i < num; i++)
//for
//初始化c陣列,長度是arr陣列+1
fill(c, num + 1);
c[0] = -1; //使得遞增數列的最小值為-1
for(i = 0; i < num; i++)
//for
//c陣列中儲存的就是結果的數字序列,列印一下
i = 1;
while(c[i] != 100)
fclose(stdin);
fclose(stdout);
return 0;
}void fill(int a, int len)
}//在陣列a中,尋找數字x
//如果存在返回其下表,如果不存在返回其該插入的位置,會覆蓋掉原來在該位置的數字
int find(int a, int clastindex, int x)
else if(x < a[mid])
else
mid = (left + right) / 2;
}//while
return left;
}//find()
通過上面的**可以看到,其實dist陣列根本沒有用到,只用c陣列就能求解問題,其實這種演算法已經不是動態規劃了,雖然它的時間複雜度比動態規劃的要好。這個演算法的根本思想就是想到乙個c陣列,這個有序遞增的陣列用來儲存最長的子串行。確實是一種很不錯的手法。
測試資料:
61042010
1513
執行結果:
讀取數字序列長度...讀取數字序列...410
13
最長單調子串行(動態規劃)
最長上公升子串行 longest increasing subsequence 簡稱lis,也有些情況求的是最長非降序子串行,二者區別就是序列中是否可以有相等的數。例如 對於序列 1,7,3,5,9,4,8 我們就會得到一些上公升的子串行,如 1,7,9 3,4,8 1,3,5,8 等等,而這些子串...
動態規劃 單調子串行相關
我們要區分一下子序列和子串。簡單的來講就是子串行是可以不連續但必須保證與給定的原陣列相同的順序,子串就是必須連續並且保證與給定的原陣列順序相同。我們討論的主要是子串行。ac code include include include include using namespace std const ...
單調遞增最長子序列問題(動態規劃)
具體描述如下 設計乙個o n2 時間的演算法,找出由n個數組成的序列的最長單調遞增子串行。輸入格式 輸入有兩行 第一行 n,代表要輸入的數列的個數 第二行 n個數,數字之間用空格格開 輸出格式 最長單調遞增子串行的長度 輸入樣例 在這裡給出一組輸入。例如 51 3 5 2 9 輸出樣例 在這裡給出相...