在一塊電路板的上、下兩端分別有n個接線柱。根據電路設計,要求用導線將上端接線柱與下端接線柱相連
,
如上圖所示,每個節點有且只連有一條線。
在制作電路板時,要求將這n條連線分布到若干絕緣層上。在同一層上的連線不相交。
這個問題是要確定將哪些連線安排在第一層上,使得該層上有盡可能多的連線(不相交)。
為了解決這個問題,我們可以 將問題簡化為這樣:
設定上接線柱為1,2,3,....,n。
下接線柱是【 1,2,3,....,n】的一個排列 設為f(i),i的值就是上接線柱的數字,
如上圖就是這樣的模型:
i 1 2 3 4 5 6 7 8 9 10
f(i) 8,7,4,2,5,1,9,3,10,6
它們一一對應。
我們還必須得到這樣一個結論:
對於上接線柱i1<i2<i3<...<ik來說。它們與下接線柱f(i)的連線之間互不相交的充要條件是:
f(i1)<f(i2)<...<f(ik)。這個結論是很顯然成立的。
因為對於i1<i2如果f(i1)>f(i2)則它們一定相交(畫出圖像來看看)
因此,我可以將這個電路布線問題,轉化為這樣的問題:
已知有一個{1,2,3,...,n}的排列,將其拆分為k個子排列,並且每個子排列都是嚴格遞增的,求子排列的最大元素個數。
例如:排列 8,7,4,2,5,1,9,3,10,6可以拆分成五個子排列{4,5,9,10}{8}{7}{2,3,6}{1} 。
它最大的元素個數是4。
排列 1,2,3,4,5,6,7,8,9,10它是遞增的,所以無需拆分,最大元素個數是10。
算法實現:
對於排列8,7,4,2,5,1,9,3,10,6。
先將記錄第一個值8,依次向后掃描至大於8的元素。如果發現8的元素,例如9,則我可以產生一個子排列{8,9}(實際上只需要更改元素數量和最大值即可),繼續掃描。
產生子排列{8,9,10}。掃描完畢后姑且認為子排列最大元素是3個。
第二次以7向后掃描,只要掃描到比它大的,就將產生一個子排列,繼續向后掃描,掃描結束后,得到排列是{7,9,10}。個數是3,與之前的比較。
第三次以4開始掃描,。。。依次下去至掃描結束。
使用遞歸算法代碼簡單,算法復雜度為O(N*N)
#include <iostream> using namespace std; #define N 10 int sub[N] = { 2, 7, 3, 4, 5, 6, 9, 8, 10, 1 }; int function(int MaxElem,int e=0,int counts=1) { if (e==N-1) { //遞歸的出口 if (sub[e] > MaxElem) counts++; return counts; } else { if (sub[e]>MaxElem) { MaxElem = sub[e]; counts++; } return function(MaxElem,e+1,counts); } } int main() { int max = 0,t; for (int i = 0; i < N; i++) { if ((t = function(sub[i]))>max) max = t; } cout << max << endl; return 0; }