組合排列。。。初中的知識用到電腦上也這麼麻煩。。

來源:互聯網
上載者:User
文章目錄
  • 下面說一下全排列:
  • 全排列遞迴演算法:
  • STL的實現方法:

編程很多時候用到排列組合。。。

組合可以搜尋解決,也可以位元運算輕鬆解決。

比如有len個數字num[]儲存,求出所有組合。。。

那麼就可以這樣寫

for (int i = 1; i < (1 << len); ++ i)// get zuhe{int len1 = 0;for (int j = 0; j < len; ++ j){if (i & (1 << j)){zuhe[len1 ++] = num[j];}}}

實際上就是有那個數那麼就有n個對應的位,1 1 1 1 1。。。。這些位可以為0或者1兩種情況,那麼從1 到2^n-1不正是代表了所有種情況嗎?然後在求為1位提出來就okle。

 

下面說一下全排列:

首先C++ STL直接調用next_permutation,注意這個函數是有順序的,從小到大,比如123,如果初始化為321,那麼下一個就沒了,已經到最後了。如果你想要獲得所有的,那麼初始化必須是123.。。。

用法就是zuhe[] ; 數組長度len1,初始化好序列。。。

do {輸出zuhe。。。。
} while (next_permutation(zuhe, zuhe + len1));//qu pai lie 

 

全排列遞迴演算法:

所謂全排列,就是將集合中元素的所有排列情況依次輸出。比如{1、2、3}的全排列為:123、132、213、231、312、321,共6種,滿足計算公式N!(N為集合中元素個數,不重複)。

當元素不重複時,全排列採用遞迴思想較容易實現,它的遞迴公式推導步驟類似:
1、要求得123的全排列,只需求得:1並上23的全排列(1 23, 1 32),2並上13的全排列(2 13, 2 31),3並上12的全排列(3 12 321)。
2、對於23的全排列,只需求得2並上3的全排列,3並上2的全排列。步驟1中13、12的全排列也類似。
3、對於3的全排列或者2的全排列,就是它們的本身。遞迴結束。

遞迴實現不重複元素全排列演算法的實現代碼(C++)如下:

//交換a和bvoid Swap(int *a, int *b){    int t = *a;    *a = *b;    *b = t;} //全排列函數。list:待排元素列表,start:起始位置下標,end:最後一個有效元素的下一個下標。void Permutation(int start, int end, int list[]){    int i;    if (start >= end) //遞迴結束,列印當前這次全排列結果,返回。    {        for (i = 0; i < end; i++)        {            printf("%d ", list[i]);        }        printf("\n");        return;    }    //對於給定的list[start...end],要使區間中每一個元素都有放在第一位的機會,    //然後開始遞迴調用自身,得到list[start+1...end]的全排列。    for (i = start; i < end; i++)    {       Swap(&list[i], &list[start]); //交換元素,使每一個元素都有放在第一位的機會。        Permutation(start+1, end, list); //遞迴調用        Swap(&list[i], &list[start]); //恢複原始的list,不影響下次遞迴調用。    }}

 

上述程式的調用方法為:

#include <iostream>using namespace std; int main(){    int a[] = {1, 2, 3};    Permutation(0, 2, a);    return 0;}

 

STL的實現方法:

當待排元素列表含有重複項時,上述演算法就需要改進,其中一種方法可以是維護一個存放不重複排列的集合,每次新產生1個排列,如果集合中不存在這個排列,則插入排列,否則,放棄。

要實現含重複元素的全排列演算法,可以參考STL中next_premutation()函數的實現方法(在algorithm.h中聲明)。該函數會將列表中元素按字典序(wiki)給出全排列中的下一個排列,它的實現演算法為:
令當前排列為P(0)P(1)P(2)...P(n-1)P(n)。則求它下一個排列的過程為,
1、從後往前遍曆,找到第一個P(i)>P(i-1)的元素,記錄下標i。比如排列1、5、2、4、3中滿足條件的元素為4,記下它的下標i = 3,因為P(i)是4,P(i-1)是2,滿足P(i)>P(i-1)。如果找不到這樣的i,則表示該序列已經是字典序中的最後一個序列,結束演算法。
2、從後往前遍曆,找到第一個P(j)>P(i-1)的數,記錄下標k。還是上面這個例子,P(i-1)為2,從後往前第一個大於P(i-1)是P(4)=3,因此記錄下j=4。
3、互換P(i-1)和P(j),得到新序列1、5、3、4、2。
4、將P[i...n]間的元素逆置,返回序列。上述例子中為逆置4和2,得到最終的序列1、5、3、2、4。

用比較通俗的例子解釋一下上述步驟:
假設現在有一個序列4、6、5、3、2、1,要求得字典序的下一個序列。首先,從後往前找到第一個i,使得P(i)>P(i-1),明顯這裡i是1,P(i)=6,這個意思是,在6之後的元素,都是按值遞減的,否則第一步求i的時候也不會找到第2個元素6才滿足條件。現在知道,從i開始到最後,其實是字典序裡的最大序列了(一直按值遞減)。第二步,拿出i的前一個元素P(i-1)=4,將它與原序列從後往前第一個大於它的元素交換位置,這裡這個與4交換的元素是5,這樣序列就變成了5、6、4、3、2、1,至此,最高位升了一級(4->5),接著要把低位的從最大變成最小(就像199之後是200,最高為從1變成2後,要把低位從最大99變成最小00),這裡的低位是最大序列6、4、3、2、1,變成最小序列只需逆置即可,變成1、2、3、4、6,原序列變為5、1、2、3、4、6,即為所求。

實現代碼如下:

/** *如果存在當前序列在字典序中的下一個排列,則返回true, *否則返回false。  */bool next_premutation(int list[], int length){    int i, j;     //步驟1:得到i。    for (i = length - 1; i > 0; i--)    {        if (list[i] > list[i-1])        {            break; //記下下標i。        }    }    if (i <= 0)     {        //表示當前排列已經是字典序中的最後一個序列,沒有下一個了。        return false;    }     //步驟2:得到j。    for (j = length - 1; j > 0 ; j--)    {        if (list[j] > list[i-1])        {            break; //記下下標j。        }    }     //步驟3:互換list[i-1]和list[j]。    int temp = list[i-1];    list[i-1] = list[j];    list[j] = temp;     //步驟4:逆置list[i...n]。    int start, end;    for (start = i, end = length-1; start < end; start++, end--)    {        int temp = list[start];        list[start] = list[end];        list[end] = temp;    }     return true;}

採用這種方法要獲得一個集合的全排列,可按下面方法調用(和stl函數next_permutation()的調用方法基本一致):

#include <iostream>
using namespace std;

int main()
{
    int list[] = {1, 2, 3, 4, 5};
    do
    {
        for (int i = 0; i < 5; i++)
        {
            printf("%d ", list[i]);
        }
        printf("\n");
    }while (next_premutation(list, 5));
    return 0;
}

 

 

 

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.