排列組合知多少–組合篇

來源:互聯網
上載者:User

這是我的第一篇博文,筆者資曆尚淺,不對之處有勞斧正。演算法之於程式,同如靈魂之於肉體,靈魂駕馭肉體,演算法主宰程式,一點也不浮誇。學好演算法,好比行走江湖有一技榜身;相反忽視演算法,“問題”就多了,難求一解,效率低下之類,自不必說。受限於此,更是難以脫穎於同行,駐足於尖端。“碼農”一說,由此得來。

切入正題,此篇主要分享3種不同的求組合演算法(c++)

方法1 遞迴:

以一組數列為例:

1 2 3 4 5 中取3個數的組合,即n=5,r=3

組合規律如下:

首先固定第一個數為5,其後就是求解  n=4, r=2的組合數,共6個組合

其次固定第一個數為4,其後就是求解  n=3, r=2的組合數,共3個組合

最後固定第一個數為3,其後就是求解  n=2, r=2的組合數,共1個組合

這就找到了n=5,r=3與n=4,r=2,n=3,r=2,以及n=2,r=2的遞迴關係。

N個數中r個數組合遞推到n-1,r-1;n-2,r-1;…r-1,r-1共n-r+1次遞迴。

遞迴停止條件是r=1.

#include "iostream.h"int a[100];void comb(int m,int k){int i,j;for(i=m;i>=k;i--){ a[k]=i; if(k>1)     comb(i-1,k-1); else {  for(j=a[0];j>0;j--)      cout<<a[j];  cout<<endl; } }}void main(){    intn=5,r=3;    a[0]=r;    comb(n,r); } 

方法2:非遞迴

通過while迴圈控制機制,採用回溯法的演算法思想,實現非遞迴的組合演算法。

以m=5,r=3為例。

數列0,1,2,3,4

第一個組合即為初始化的0,1,2,用數組a[100]的a[0],a[1],a[2]儲存。 a[cur]標誌當前控制的是a[0],a[1],a[2]中的哪一個(初始選擇最後一個,即為a[2]).通過a[cur]-cur<=m-r可以判斷是否越界。比如:若a[cur]為a[2]時,當a[2]取3,3-2<=5-3 故沒越界,此刻組合為0,1,3;當a[2]取5時,5-2>5-3,組合輸出為0,1,5很顯然5根本取不到,故越界。

若不滿足a[cur]-cur<=m-r ,那麼執行a[--cur]++,回溯到上一層,a[cur]由a[2]變為a[1],同時a[1]=1變為a[1]=2,a[2]則變為3,組合即為0,2,3.若此時滿足a[cur]-cur<m-r,表示還有數列還有空間,cur=r-1,即a[cur]由a[1]變為a[2]繼續迴圈。不滿足,則繼續執行迴圈,下次a[cur]將回溯到a[0]。

 #include "iostream.h"int a[100];void comb(int m,int r){        int cur;                   for(int i=0;i<r;i++)        a[i]=i; cur=r-1;    do{              if (a[cur]-cur<=m-r ){                  for (int j=0;j<r;j++)             cout<<a[j] <<"  ";           cout<<endl;         a[cur]++;         continue;        }        else{            if (cur==0){             break;            }              a[--cur]++;         for(int i=1;i<r-cur;i++){              a[cur+i]=a[cur]+i;            }            if(a[cur]-cur<m-r)               cur=r-1;                         }     } while (1);}void main (){    int n;cin>>n;comb(n,i);           }

遞迴的方法一般可讀性強,代碼量較小,設計難度小,使用範圍廣,但佔用空間大,時間複雜度大(即耗時間長度)。而非遞迴的方法一般空間,時間效率都高,但可讀性差,適用範圍小且設計難度大。

但在強調軟體維護優先於軟體效率的今天,除了少數像求階層和斐波那契數列那樣的尾遞迴程式,其他需要設定棧才能轉換為非遞迴的程式就沒有轉換非遞迴的必要。(此結論參考演算法設計與分析第2版)

 

方法3:for迴圈解決法

以n=5,r=3為例,所有組合如下:

1 2 3

1 2 4

1 2 5

1 3 4

1 3 5

1 4 5

2 3 4

2 3 5

2 4 5

3 4 5

運用我們找規律的邏輯能力,不難發現這些組合滿足兩個特點:1.各不相同 2.前面的數小於後面的數。所以演算法設計如下:

#include “iostream.h”void main(){int n=5,i,j,k;for(i=1;i<=n;i++)for(j=1;j<=n;j++)for(k=1;k<=n;k++)if(i<j&&j<k){t=t+1;cout<<i<<” ”<<j<<””<<k<<endl;}}

此方法代碼最少,但因for迴圈機制的局限性,不能實現n,r的通用求法。

組合問題是一個經典不衰的問題,求解方法當然不止這些,例如2進位標記法,子集數搜尋法之類會在子集數專欄介紹。最後,我的博文分享就此開始,作此以助人,同時也自勉,願中國軟體開發聯盟越走越遠。

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在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.