C++中求組合數的各種方法總結詳解

來源:互聯網
上載者:User

【問題】 組合問題

問題描述:找出從自然數1、2、... 、n中任取r個數的所有組合。例如n=5,r=3的所有組合為:

1,2,3
1,2,4
1,3,4
2,3,4
1,2,5
1,3,5
2,3,5
1,4,5
2,4,5
3,4,5

用程式實現有幾種方法:

1)窮舉法

程式如下
【程式】
#include<stdio.h>
const int n=5,r=3;
int i,j,k,counts=0;

int main()
{
for(i=1;i<=r ;i++)
for(j=i+1;j<=r+1;j++)
for( k=j+1;k<=r+2;k++){
counts++;
printf("%4d%4d%4d/n",i,j,k);
}
printf("%d",counts);
return 0;
}
但是這個程式都有一個問題,當r變化時,迴圈重數改變,這就影響了這一問題的解,即沒有一般性。

2)遞迴法
分析所列的10個組合,可以採用這樣的遞迴思想來考慮求組合函數的演算法。
設函數為void comb(int m,int k)為找出從自然數1、2、... 、m中任取k個數的所有組
合。當組合的第一個數字選定時,其後的數字是從餘下的m-1個數中取k-1數的組合。這
就將求m個數中取k個數的組合問題轉化成求m-1個數中取k-1個數的組合問題。設函數引
入工作數組a[ ]存放求出的組合的數字,約定函數將確定的k個數字組合的第一個數字放
在a[k]中,當一個組合求出後,才將a[ ]中的一個組合輸出。第一個數可以是m、m-1、
...、k,函數將確定組合的第一個數字放入數組後,有兩種可能的選擇,因還未去頂組
合的其餘元素,繼續遞迴去確定;或因已確定了組合的全部元素,輸出這個組合。細節
見以下程式中的函數comb。
【程式】
#include <time.h>
#include <iostream>

using namespace std;

# define MAXN 100
int a[MAXN];
int counts=0;

void printtime(void) //列印目前時間的函數
{
char tmpbuf[128];
time_t ltime;
struct tm *today;

time(&ltime);
today = localtime(&ltime );
strftime(tmpbuf,128,"%Y-%m-%d %H:%M:%S",today);
cout<<tmpbuf<<endl;
}

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
{
counts++;
/*
for (j=a[0];j>0;j--)
printf("%4d",a[j]);
printf("/n");
*/
}
}
}

int main()
{

int m,r;
cout<<"m"<<endl;
cin>>m;
cout<<"r"<<endl;
cin>>r;
counts=0;
a[0]=r;
printtime();
comb(m,r);
cout<<counts<<endl;
printtime();
return 0;
}

這是我在網上找到的程式,稍微修改了一下。程式寫的很簡潔,也具有通用性,解決了問題。

3)回溯法

採用回溯法找問題的解,將找到的組合以從小到大順序存於a[0],a[1],…,a[r-1]
中,組合的元素滿足以下性質:

(1) a[i+1]>a[i],後一個數字比前一個大;
(2) a[i]-i<=n-r+1。
按回溯法的思想,找解過程可以敘述如下:
首先放棄組合數個數為r的條件,候選組合從只有一個數字1開始。因該候選
解滿足除問題規模之外的全部條件,擴大其規模,並使其滿足上述條件(1),候選組合
改為1,2。繼續這一過程,得到候選組合1,2,3。該候選解滿足包括問題規模在內的全
部條件,因而是一個解。在該解的基礎上,選下一個候選解,因a[2]上的3調整為4,以
及以後調整為5都滿足問題的全部要求,得到解1,2,4和1,2,5。由於對5不能再作調
整,就要從a[2]回溯到a[1],這時,a[1]=2,可以調整為3,並向前試探,得到解1,3,
4。重複上述向前試探和向後回溯,直至要從a[0]再回溯時,說明已經找完問題的全部
解。

在網上我始終沒有找到可以正常執行的完整程式,所以我只好花了一天的時間來自己來寫這個程式,並且改變輸出從0開始而不是從1開始,這樣做的目的是 為了擴充程式的用途,適應c/c++語言的需要,這樣輸出就可以當作要選擇的組合數組的地址序列,可以對長度為n任意類型數組找出r個組合。我對它進行了 最佳化,如果你認為還有可以最佳化的地方,請不惜賜教,。^_^

#include <time.h>
#include <iostream>
#include <iomanip>
using namespace std;

# define MAXN 100
int a[MAXN]; //定位元組,用於指示選取元素集合數組的位置,選取元素集合數組0 起始
void comb(int m,int r)
{
int cur;//指示定位元組中哪個成員正在移進

unsigned int count=0;

//初始化定位元組,0 起始的位置 ,開始的選擇必是位置 0,1,2
for(int i=0;i<r;i++)
a[i]=i;

cur=r-1;//當前是最後一個成員要移進

do{
if (a[cur]-cur<=m-r ){

count++;
/*
for (int j=0;j<r;j++)
cout<<setw(4)<<a[j];
cout<<endl;
*/
a[cur]++;

continue;
}
else{
if (cur==0){
cout<<count<<endl;
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 printtime(void) //列印目前時間的函數
{
char tmpbuf[128];
time_t ltime;
struct tm *today;

time(&ltime);
today = localtime(&ltime );
strftime(tmpbuf,128,"%Y-%m-%d %H:%M:%S",today);
cout<<tmpbuf<<endl;
}

int main (int argc, char *argv[])
{

int m,r;
cout<<"m"<<endl;
cin>>m;
cout<<"r"<<endl;
cin>>r;
printtime();
comb(m,r);
printtime();
return(0);
}

同上面的遞迴的程式進行比較,同樣用g++ o2最佳化。當n=40,r=11,屏蔽掉輸出,得到的結果都是2311801440項,遞迴程式用了23至24秒,回溯用了19至20秒。

4)利用數組

定義:從n個數中取出m個數的組合。
實現機理:先建立一個字串數組,其下標表示 1 到 n 個數,數組元素的值為1表示其下標代表的數被選中,為0則沒選中。
然後初始化,將數組前 m 個元素置 1,表示第一個組合為前 m 個數。
然後從左至右掃描數組元素值的 10 組合,找到第一個 "10" 後交換 1 和 0 的位置,變為 01,而後將該10組合前的1和0重新組合(1放在前邊,其個數為10組合前1的個數,0放在後邊,其個數為10前0的個數,而後接10的倒轉組合 01)。當m 個 1 全部移動到最右端時,就得到了最後一個組合。
例如求 5 中選 3 的組合:
1 1 1 0 0 //1,2,3
1 1 0 1 0 //1,2,4
1 0 1 1 0 //1,3,4
0 1 1 1 0 //2,3,4
1 1 0 0 1 //1,2,5
1 0 1 0 1 //1,3,5
0 1 1 0 1 //2,3,5
1 0 0 1 1 //1,4,5
0 1 0 1 1 //2,4,5
0 0 1 1 1 //3,4,5

相關文章

聯繫我們

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