青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品

C++ Jounior

once setback,once inspiration,once self-awareness
重要的是這個磨練過程,而不是結果,要的是你粗壯的腿,而不是你身上背的那袋鹽巴

 

全排列的生成算法

全排列的生成算法就是對于給定的字符集,用有效的方法將所有可能的全排列無重復無遺漏地枚舉出來。任何n個字符集的排列都可以與1~n的n個數字的排列一一對應,因此在此就以n個數字的排列為例說明排列的生成法。
n個字符的全體排列之間存在一個確定的線性順序關系。所有的排列中除最后一個排列外,都有一個后繼;除第一個排列外,都有一個前驅。每個排列的后繼都可以從 它 的前驅經過最少的變化而得到,全排列的生成算法就是從第一個排列開始逐個生成所有的排列的方法。
全排列的生成法通常有以下幾種:
字典序法
遞增進位數制法
遞減進位數制法
鄰位交換法
遞歸類算法
1.字典序法
字典序法中,對于數字1、2、3......n的排列,不同排列的先后關系是從左到右逐個比較對應的數字的先后來決定的。例如對于5個數字的排列12354和12345,排列12345在前,排列12354在后。按照這樣的規定,5個數字的所有的排列中最前面的是12345,最后面的是54321。
字典序算法如下:
設P是1~n的一個全排列:p=p1p2......pn=p1p2......pj-1pjpj+1......pk-1pkpk+1......pn
1)從排列的右端開始,找出第一個比右邊數字小的數字的序號j(j從左端開始計算),即? j=max{i|pi<pi+1}
2)在pj的右邊的數字中,找出所有比pj大的數中最小的數字pk,即 k=max{i|pi>pj}(右邊的數從右至左是遞增的,因此k是所有大于pj的數字中序號最大者)
3)對換pi,pk
4)再將pj+1......pk-1pkpk+1pn倒轉得到排列p''=p1p2.....pj-1pjpn.....pk+1pkpk-1.....pj+1,這就是排列p的下一個下一個排列。
例如839647521是數字1~9的一個排列。從它生成下一個排列的步驟如下:
自右至左找出排列中第一個比右邊數字小的數字4??????????? 839647521
在該數字后的數字中找出比4大的數中最小的一個5??????? 839647521
將5與4交換??????????????????????????????????????????????????????????????????????????? 839657421
將7421倒轉????????????????????????????????????????????????????????????????????????? 839651247
所以839647521的下一個排列是839651247。
2.遞增進位數制法
在遞增進位制數法中,從一個排列求另一個排列需要用到中介數。如果用 ki表示排列p1p2...pi...pn中元素pi的右邊比pi小的數的個數,則排列的中介數就是對應的排列k1 ...... ki...... kn-1。
例如排列839647521的中介數是72642321,7、2、6、......分別是排列中數字8、3、9、......的右邊比它小的數字個數。
中介數是計算排列的中間環節。已知一個排列,要求下一個排列,首先確定其中介數,一個排列的后繼,其中介數是原排列中介數加1,需要注意的是,如果中介數的末位kn-1+1=2,則要向前進位,一般情形,如果ki+1=n-i+1,則要進位,這就是所謂的遞增進位制。例如排列839647521的中介數是72642321,則下一個排列的中介數是67342221+1=67342300(因為1+1=2,所以向前進位,2+1=3,又發生進位,所以下一個中介數是67342300)。
得到中介數后,可根據它還原對應得排列。算法如下:
中介數k1、k2、......、kn-1的各位數字順序表示排列中的數字n、n-1、......、2在排列中距右端的的空位數,因此,要按k1、k2、......、kn-1的值從右向左確定n、n-1、......、2的位置,并逐個放置在排列中:i放在右起的ki+1位,如果某位已放有數字,則該位置不算在內,最后一個空位放1。
因此從67342300可得到排列849617523,它就是839647521的后一個排列。因為9最先放置,k1=6,9放在右起第7位,空出6個空位,然后是放8,k2=7,8放在右起第8位,但9占用一位,故8應放在右起第9位,余類推。
3.遞減進位制數法
在遞增進位制數法中,中介數的最低位是逢2進1,進位頻繁,這是一個缺點。把遞增進位制數翻轉,就得到遞減進位制數。
839647521的中介數是67342221(k1k2…kn-1),倒轉成為12224376(kn-1…k2k1),這是遞減進位制數的中介數:ki(i=n-1,n-2,…,2)位逢i向ki-1位進1。給定排列p,p的下一個排列的中介數定義為p的中介數加1。例如p=839647521,p的中介數為12224376,p的下一個排列的中介數為12224376+1=12224377,由此得到p的下一個排列為893647521。
給定中介數,可用與遞增進位制數法類似的方法還原出排列。但在遞減進位制數中,可以不先計算中介數就直接從一個排列求出下一個排列。具體算法如下:
1)如果p(i)=n且i<>n,則p(i)與p(i-1)交換
2)如果p(n)=n,則找出一個連續遞減序列9、8、......、i,將其從排列左端刪除,再以相反順序加在排列右端,然后將i-1與左邊的數字交換
例如p=893647521的下一個排列是983647521。求983647521的下一個排列時,因為9在最左邊且第2位為8,第3位不是7,所以將8和9從小到大排于最右端364752189,再將7與其左方數字對調得到983647521的下一個排列是367452189。又例如求987635421的下一個排列,只需要將9876從小到大排到最右端并將5與其左方數字3對調,得到534216789。
4.鄰位對換法
鄰位對換法中下一個排列總是上一個排列某相鄰兩位對換得到的。以4個元素的排列為例,將最后的元素4逐次與前面的元素交換,可以生成4個新排列:
1 2 3 4? 1 2 4 3? 1 4 2 3? 4 1 2 3
然后將最后一個排列的末尾的兩個元素交換,再逐次將排頭的4與其后的元素交換,又生成四個新排列:
? 4 1 3 2? 1 4 3 2? 1 3 4 2? 1 3 2 4
再將最后一個排列的末尾的兩個元素交換,將4從后往前移:
3 1 2 4? 3 1 4 2? 3 4 1 2?? 4 3 1 2
如此循環既可求出全部排列。
5.元素增值法(n進制法)
1)從原始排列p=p1p2......pn開始,第n位加n-1,如果該位的值超過n,則將它除以n,用余數取代該位,并進位(將第n-1位加1)
2)再按同樣方法處理n-1位,n-2位,......,直至不再發生進位為止,處理完一個排列就產生了一個新的排列
3)將其中有相同元素的排列去掉
4)當第一個元素的值>n則結束
以3個數1、2、3的排列為例:原始排列是1? 2? 3,從它開始,第3個元素是3,3+2=5,5 Mod 3=2,第2個元素是2,2+1=3,所以新排列是1 3 2。通過元素增值,順序產生的排列是:1? 2? 3,1? 3? 2,2? 1? 1,2? 1? 3,2? 2? 2,2? 3? 1,2? 3? 3,3? 1? 2,3? 2? 1
有下劃線的排列中存在重復元素,丟棄,余下的就是全部排列。
6.遞歸類算法
全排列的生成方法用遞歸方式描述比較簡潔,實現的方法也有多種。
1)回溯法
回溯法通常是構造一顆生成樹。以3個元素為例;樹的節點有個數據,可取值是1、2、3。如果某個為0,則表示尚未取值。
初始狀態是(0,0,0),第1個元素值可以分別挑選1,2,3,因此擴展出3個子結點。用相同方法找出這些結點的第2個元素的可能值,如此反復進行,一旦出現新結點的3個數據全非零,那就找到了一種全排列方案。當嘗試了所有可能方案,即獲得了問題的解答。
2)遞歸算法
如果用P表示n個元素的排列,而Pi表示不包含元素i的排列,(i)Pi表示在排列Pi前加上前綴i的排列,那么,n個元素的排列可遞歸定義為:
如果n=1,則排列P只有一個元素i
如果n>1,則排列P由排列(i)Pi構成(i=1、2、....、n-1)。
根據定義,容易看出如果已經生成了k-1個元素的排列,那么,k個元素的排列可以在每個k-1個元素的排列Pi前添加元素i而生成。例如2個元素的排列是1? 2和2?? 1,對與個元素而言,p1是2? 3和3? 2,在每個排列前加上1即生成1 2 3和1 3 2兩個新排列,p2和p3則是1? 3、3? 1和1? 2、2? 1,按同樣方法可生成新排列2 1 3、2 3 1和3 1 2、3 2 1。
3)循環移位法
如果已經生成了k-1個元素的排列,則在每個排列后添加元素k使之成為k個元素的排列,然后將每個排列循環左移(右移),每移動一次就產生一個新的排列。
例如2個元素的排列是1 2和2 1。在1 2 后加上3成為新排列1 2 3,將它循環左移可再生成新排列2 3 1、3 1 2,同樣2 1 可生成新排列2 1 3、1 3 2和3 2 1。
上述算法的程序代碼如下:

#include < iostream.h >
#include
< time.h >
const ?maxn = 100 ;

void ?outp( int ?p[], int ?n)????????? // 輸出一個排列????
{
?
int ?i;
?cout
<< " ? " ;
?
for (i = 1 ;i <= n;i ++ )
???cout
<< p[i] << " ? " ;
??cout
<< endl;
}


void ?swap( int ? & ?x, int ? & ?y)
{
?
int ?t = x;
?x
= y;
?y
= t;
}


void ?dict( int ?p[], int ?n)????????? // 字典序法
{
?
int ?i,j;
?outp(p,n);
?i
= n - 1 ;
?
while (i > 0 )
?
{
??
if ?(p[i] < p[i + 1 ])
??
{
???
for (j = n;j >= i + 1 ;j -- )
????
if (p[i] <= p[j])? break ;
???swap(p[i],p[j]);
???
for (j = n;j >= 1 ;j -- )
???
{
????i
+= 1 ;
????
if ?(i >= j)? break ;
????swap(p[i],p[j]);
???}

???outp(p,n);
???i
= n;
??}

??i
-= 1 ;
?}
;
}


bool ?midn( int ?m[], int ?n)
{
?
int ?k = n - 1 ;
?
while ( 1 )
?
{
??m[k]
+= 1 ;
??
if (m[k] < n - k + 1 ) break ;
??m[k]
= 0 ;
??k
-= 1 ;
?}

?
int ?s = 0 ;
?
bool ?b = false ;
?
for (?k = 1 ;k <= n;)
??s
+= m[k ++ ];
?
if (s == 0 )?b = true ;
?
return ?b;
}

void ?incr( int ?p[], int ?n)
{
?
int ?m[maxn];
?
int ?i,j,a;
?
for (i = 1 ;i <= n;)
??m[i
++ ] = 0 ;
?
while (i > 0 )
?
{
??
for (i = 1 ;i <= n;)
???p[i
++ ] = 0 ;
??
for (i = 1 ;i <= n;i ++ )
??
{
???a
= m[i] + 1 ;
???j
= n;
???
while (j > 0 )
???
{
????
if (p[j] == 0 )
????
{
?????a
-= 1 ;
?????
if (a == 0 )? break ;
????}

????j
-= 1 ;
???}

???p[j]
= n - i + 1 ;
??}

??outp(p,n);
??
if ?(midn(m,n) == true )? break ;??
?}

}



void ?degr( int ?p[], int ?n)
{
?
int ?i,j;
?
while ( 1 )
?
{
??outp(p,n);
??
if (p[ 1 ] != n)
??
{
???i
= 0 ;
???
while (p[ ++ i] != n);????
???swap(p[i],p[i
- 1 ]);
??}

??
else
??
{
???i
= 1 ;
???
while (i < n)
???
{
????
if (p[i] != p[i + 1 ] + 1 )? break ;
????i
+= 1 ;
???}

???
if (i == n) break ;??????
???j
= i;
???
while (p[i] != p[j] - 1 )
????i
+= 1 ;
???swap(p[i],p[i
- 1 ]);
???
for (i = 1 ;i <= n - j;)
????p[i
++ ] = p[i + j];
???
for ?(i = 1 ;i <= j;i ++ )
????p[n
- i + 1 ]? = n - i + 1 ;???
??}

?}

}


void ?conv( int ?p[], int ?n)
{
?
long ?m = 1 ;
?
for ( int ?i = 3 ;i < n;)
??m
= m * i ++ ;
?
for (i = 1 ;i < m;i ++ )
?
{
??outp(p,n);
??
for ( int ?j = n;j > 1 ;j -- )
??
{
???swap(p[j],p[j
- 1 ]);
???outp(p,n);
??}

????????swap(p[n],p[n
- 1 ]);
??outp(p,n);
??
for (j = 1 ;j < n;j ++ )
??
{
???swap(p[j],p[j
+ 1 ]);
????????????outp(p,n);
??}

????????swap(p[
1 ],p[ 2 ]);
?}

}


bool ?test( int ?p[],? int ?n)
{
?
bool ?b = false ;
?
for ( int ?i = 1 ;i <= n;i ++ )
??
for ( int ?j = i + 1 ;j <= n;j ++ )
???
if (p[i] == p[j])?
???
{
????b
= true ;
????
break ;
???}

????
return ?b;
}


void ?Nnum( int ?p[], int ?n)
{
?
while (n > 0 )
?
{
??
if ?(test(p,n) == false )?outp(p,n);
??p[n]
+= n - 1 ;?????????????????????????????
????????
for ( int ?j = n;j > 1 ;j -- )
??
{
??????????
if (p[j] > n)
????
{
?????p[j]
%= n;?????????????????????????????
??????????????p[j
- 1 ] += 1 ;?????????????????????
??????????????
if (p[ 1 ] > n)
?????
{
??????n
= 0 ;
??????
break ;
?????}

????}

??}
????????????????????????????????
?}

}


void ?recu( int ?p[], int ?n, int ?k)
{
?
if (k == n)?
??outp?(p,n);
?
else
?
{
??
for ( int ?i = k;i <= n;i ++ )
????????
{
???swap?(p[k],p[i]);
???recu(p,?n,k
+ 1 );
???swap?(p[k],p[i]);?
??}

????}

}


void ?cyc( int ?p[], int ?n, int ?k)
{
?
if ?(k > n)
??outp(p,n);
?
else
?
{
??
for ( int ?i = 0 ;i < k;i ++ )
??
{
???
int ?t = p[ 1 ];
???
for ( int ?j = 2 ;j <= k;j ++ )
????p[j
- 1 ] = p[j];
????????????p[k]
= t;
???cyc(p,n,k
+ 1 );
????????}

?}


}


void ?remo( int ?p[], int ?n, int ?k)
{
?
bool ?b;
?
if ?(k > n)
??outp?(p,n);
?
else
?
{
???????
for ( int ?i = 1 ;i <= n;i ++ )
????
{
?????b
= false ;
?????p[k]
= i;??????????????????
???????????
for ( int ?j = 1 ;j < k;j ++ )
??????
if (i == p[j])
????
{
??????b
= true ;
??????
break ;
????}

???
if (b == false )?remo(p,n,k + 1 );?????
????}

????}

}


void ?main()
{
?
int ?i,j,m;
?
int ?p[maxn];
?
int ?n;
?clock_t?start,finish;
?cout
<< " 輸入排列元素總數?n= " ;
?cin
>> n;
?
for (i = 1 ;i <= n;i ++ )
??p[i]
= i;?
?cout
<< " 1——字典序法 " << endl;
?cout
<< " 2——遞增進位數制法 " << endl;
?cout
<< " 3——遞減進位數制法 " << endl;
?cout
<< " 4——鄰位交換法 " << endl;
?cout
<< " 5——n進制數法 " << endl;
?cout
<< " 6——遞歸生成法 " << endl;
?cout
<< " 7——循環移位法 " << endl;
?cout
<< " 8——回溯法 " << endl;
?cout
<< " 請選擇:? " ;
?cin
>> m;
?start
= clock();
?
switch ?(m)
?
{
????
case ? 1 :dict(p,n); break ;
????
case ? 2 :incr(p,n); break ;?
???????
case ? 3 :degr(p,n); break ;??
????
case ? 4 :conv(p,n); break ;
???????
case ? 5 :Nnum(p,n); break ;?
???????
case ? 6 :recu(p,n, 1 ); break ;
????
case ? 7 :cyc(p,n, 1 ); break ;????
???????
case ? 8 :remo(p,n, 1 );
?}

?finish
= clock();
?cout
<< " 程序執行時間: "
??
<< ( double )(finish - start) / CLOCKS_PER_SEC << " " << endl;
}
reference : http://course.zjnu.cn/quyt/bbs/ftbbs.asp?id=115
?void?sort(char?s[]){};
?
char?p[]?="????";
?
void?perm(char?s[],?int?i,?int?n)
?
{
??????
int?j;
??????
char?temp;
??????printf(
"perm?i=%d?????????s=%s??p=%s\n",i,s,p);
??????
for(j=0;j<n;++j)
??????
{
??????????
if(j!=0?&&?s[j]==s[j-1]);
??????????
else?if(s[j]!='@')
??????????
{
??????????????p[i]
=s[j];
??????????????s[j]
='@';
??????????????
if(i==n-1)
??????????????
{
??????????????????p[n]
='\0';
??????????????????printf(
"===============output?:?%s\n\n",?p);
??????????????}

??????????????
else
??????????????
{
??????????????????printf(
"?????i=%d??j=%d????s=%s??p=%s\n",i,j,s,p);
??????????????????perm(s,i
+1,n);
??????????????}

??????????????s[j]
=p[i];
??????????}

??????}

?}

?
void?Test31()?
?
{
??????
char?s[]=?"112";
??????sort(s);
??????perm(s,
0,strlen(s));
??}

posted on 2008-04-02 09:06 snowball 閱讀(1477) 評論(1)  編輯 收藏 引用 所屬分類: 算法+數據結構

評論

# re: 全排列的生成算法 2008-09-01 18:42 phy

遞歸版的算法還是比較容易理解的,非遞歸版的雖然知道怎么做,卻不知道為什么可以那樣做。  回復  更多評論   

導航

留言簿(1)

隨筆分類

友情鏈接

搜索

最新隨筆

最新評論

閱讀排行榜

青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品
  • <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>
            欧美日韩一区高清| 欧美中文字幕视频在线观看| 亚洲电影免费| 99国产精品久久久久老师| 亚洲欧美高清| 亚洲一区二区三区欧美| 玖玖视频精品| 国产亚洲人成网站在线观看| 99伊人成综合| 欧美成人精品福利| 欧美亚洲免费电影| 欧美日韩国产欧| 亚洲福利小视频| 久久久亚洲国产美女国产盗摄| 亚洲精品一区二区三| 蜜桃久久av| 国产精品v欧美精品∨日韩| 亚洲经典三级| 久久综合狠狠| 亚洲欧美国产一区二区三区| 久久国产99| 一区二区三区欧美| 国产欧美一区二区三区视频| 久久久国产精品一区| 久久亚洲综合色一区二区三区| 在线精品亚洲一区二区| 亚洲第一天堂av| 国产精品xnxxcom| 欧美一区二区三区啪啪| 久久精品亚洲国产奇米99| 亚洲第一视频| 99精品国产一区二区青青牛奶| 亚洲人午夜精品| 久久久av水蜜桃| 亚洲国产精品成人综合| 蘑菇福利视频一区播放| 狼人社综合社区| 亚洲激情视频网| 99热免费精品| 国产午夜久久久久| 欧美国产日本高清在线| 欧美理论在线播放| 午夜精品区一区二区三| 久久成人综合视频| 亚洲精品自在久久| 午夜精品短视频| 亚洲免费观看| 欧美一区二区黄色| 在线亚洲一区| 久久久999成人| 亚洲在线免费视频| 久久天天躁狠狠躁夜夜爽蜜月| 一片黄亚洲嫩模| 欧美中文字幕视频| 亚洲一区二区视频| 久久综合久久88| 欧美一级专区| 欧美激情久久久久| 久久天堂精品| 欧美午夜一区二区福利视频| 老司机免费视频久久| 欧美午夜a级限制福利片| 嫩模写真一区二区三区三州| 国产精品视频1区| 亚洲精品午夜| 亚洲精品无人区| 久久久女女女女999久久| 亚洲欧美在线免费| 欧美激情一区在线观看| 久久久久9999亚洲精品| 欧美三级韩国三级日本三斤| 亚洲激情校园春色| 亚洲国产精品一区二区第一页| 欧美一区二区日韩一区二区| 亚洲欧美日韩一区| 国产精品av免费在线观看| 亚洲人体影院| 亚洲作爱视频| 欧美日韩成人综合| 亚洲激情av在线| 日韩视频免费| 欧美精品一区二区在线观看| 亚洲人成网站色ww在线| 99re6热在线精品视频播放速度| 美脚丝袜一区二区三区在线观看 | 国产精品久久久久久久久借妻 | 欧美午夜免费| 国产精品久久网| 亚洲国产精品久久久久秋霞不卡| 亚洲专区欧美专区| 亚洲视频成人| 欧美性猛交xxxx乱大交退制版| 亚洲精品一区中文| 亚洲调教视频在线观看| 欧美日韩系列| 99精品热视频| 新狼窝色av性久久久久久| 国产精品v欧美精品v日本精品动漫 | 亚洲国产精品一区在线观看不卡 | 午夜亚洲影视| 久久国内精品自在自线400部| 国产精品一页| 久久精精品视频| 亚洲高清久久网| 一区二区欧美在线| 国产精品乱码一区二区三区| 欧美一级视频一区二区| 久久久久久久久久码影片| 一区二区三区在线视频免费观看| 久久久美女艺术照精彩视频福利播放| 麻豆精品传媒视频| 亚洲精品一区二区网址| 欧美日韩三级| 欧美一区网站| 亚洲高清不卡在线观看| 99精品视频免费观看视频| 欧美日韩在线观看视频| 性色av香蕉一区二区| 亚洲成色777777在线观看影院| 在线视频亚洲一区| 国产精品老女人精品视频| 亚洲尤物影院| 欧美激情第五页| 亚洲小视频在线观看| 国产一区二区三区在线观看免费| 久久永久免费| aa级大片欧美| 免费成人高清视频| 亚洲一区二区三区激情| 一区在线视频观看| 欧美视频亚洲视频| 久久久av毛片精品| 亚洲一区国产视频| 亚洲国产小视频| 欧美在线影院| 一区二区三区日韩欧美精品| 黄色一区二区在线| 国产精品久久福利| 欧美大学生性色视频| 欧美在线观看视频| 一区二区三区欧美| 亚洲黄色天堂| 你懂的视频欧美| 久久精品视频在线| 亚洲一区二区在线| 亚洲精品欧美精品| 亚洲第一在线| 黄色欧美日韩| 国产精品h在线观看| 欧美成人嫩草网站| 久久www成人_看片免费不卡| 99精品国产福利在线观看免费| 国产精品jvid在线观看蜜臀 | 久久久久一区二区三区| 99天天综合性| 亚洲三级毛片| 欧美黄色aa电影| 久久午夜电影| 欧美一区二区在线| 亚洲在线网站| 一本色道精品久久一区二区三区 | 亚洲成人在线观看视频| 国产精品日韩在线一区| 欧美三区在线视频| 欧美精品国产精品| 欧美大香线蕉线伊人久久国产精品| 久久精品国产99精品国产亚洲性色| 亚洲免费中文字幕| 亚洲欧美日韩国产综合在线| 亚洲一区二区三区久久| 一区二区三区精品视频| 日韩一级免费| 99热免费精品| 亚洲一区久久久| 亚洲综合色丁香婷婷六月图片| 亚洲一区二区三区免费在线观看 | 伊大人香蕉综合8在线视| 狠狠色狠狠色综合| 黄色亚洲在线| 黑人极品videos精品欧美裸| 一区二区三区在线不卡| 1769国内精品视频在线播放| 亚洲国产精品一区制服丝袜| 亚洲肉体裸体xxxx137| 亚洲精品色婷婷福利天堂| 亚洲激情婷婷| 一区二区高清视频在线观看| 亚洲视频一区二区| 午夜日韩激情| 久久精品午夜| 欧美激情在线播放| 亚洲精选在线| 午夜日韩在线| 久久尤物电影视频在线观看| 欧美日韩国产a| 国产婷婷精品| 亚洲福利视频网| 亚洲婷婷综合久久一本伊一区| 新67194成人永久网站| 久久偷看各类wc女厕嘘嘘偷窃|