1. 程式人生 > >C++:排列組合演算法

C++:排列組合演算法

轉載請註明出處

1 介紹

排列(Permutation)和組合(Combination)是兩個基礎的數學概念。

計算排列與組合可以解決一些實際的工程問題,掌握排列組合計算的方法是十分重要的。

目前,網上已經有一些計算排列組合的演算法,比如[1]。

這裡我也給出一個組合計算方法。該計算方法採用了分治的思想,程式碼實現採用了遞迴的方式。

2 組合演算法

2.1 設計思路

組合問題:在序列An={1,2,3,4,5,6,...,n}中選擇m個數一共有C(n,m)種組合,求解所有的組合。

例如,C(3,2)=3. 所有的組合分別是{1,2},{1,3},{2,3}。

思路:

我的演算法採用了分治的思想:將一個大的問題拆分成很多個子問題,先解決子問題,所有子問題的解共同組成了大問題的解。

接下來我以求組合C(5,3)為例進行說明:

假設C(5,3)的所有組合形成的集合是E。我們可以將組合結果E分成兩類:A類是含有5的組合,B類是不含5的組合;

同理,我們可以將B類分成B1和B2兩類:B1類是含有4的組合(且不含5的組合),B2類是不含4的組合(且不含5的組合);

同理,我們可以將B2類分成B21和B22兩類:B21類是含有3的組合(且不含5、4的組合),B22類是不含3的組合(且不含5、4的組合)。注意,此時B22類是不成立的(應為不含3、4、5,只剩下1、2兩個元素。而例子要求解C(5,3)至少需要3個元素)。

以上分類方法可以保證E=B21 U B1 U A

其中,

對於A類組合,我們只需要求解子問題C(4,2),之後再在子問題的結果中加入5即可得到A類組合;

對於B1類組合,我們只需要求解子問題C(3,2),之後再在子問題的結果中加入4即可得到B1類組合;

對於B21類組合,我們只需要求解子問題C(2,2),之後再在子問題的結果中加入3即可得到B21類組合;

A類組合、B1類組合、B21組合組成了C(5,3)的所有組合。

可以發現,問題C(5,3)已經降維成三個子問題:C(4,2),C(3,2) 和C(2,2)。利用遞迴的方法即可實現最終結果的求解。

2.2 演算法複雜度

2.2.1 時間複雜度

所有的組合演算法的時間複雜度都至少是C(n,m)=n!/[m!*(n-m!)]。本演算法的時間複雜度也是階乘量級的。

2.2.2 空間複雜度

由於採用了遞迴的實現方式,本演算法的空間複雜度很高,很有可能造成記憶體溢位。建議採用非遞迴的方法實現組合計算。

2.3 原始碼

下面是原始碼:

/*****************************************************************************************************************************
        時間複雜度:
        空間複雜度:
        功能:求排列組合Cij
        輸入引數:
                int i                :        總數
                int j                :          組合數
                vector<int>r:        用於儲存臨時結果的向量,大小必須等於num 
                int num                :        組合數
                vector<vector<int> > & result        :        用於儲存最終所有結果的二維向量 
        返回引數:
                void
        注意: 
                首先建立兩個向量作為函式的輸入引數                
                vector<int> r(num);                                //num為組合數 
                vector<vector<int> > result;        //儲存最終結果 
        使用樣例:
                vector<int> resulttemp(3);
                vector<vector<int> > result;
                Cij(6,3,resulttemp,3,result); 
*****************************************************************************************************************************/


void Cij(int i, int j,vector<int> &r,int num,vector<vector<int> > & result)
{
        //排列組合公式Cij
        //cout << n << ' ' << i << ' ' << j << endl;
        if (j == 1)
        {
                for (int k = 0; k < i; k++)
                {
                        vector<int> temp(num);
                        r[num - 1] = k;
                        for (int i = 0; i < num;i++)
                        {
                                temp[i]=r[i];
                                //cout << r[i] << ' ';
                        }
                        result.push_back(temp);
                        //cout << endl;
                }
        }
        else if (j == 0)
        {
                //do nothing!
        }
        else
        {
                for (int k = i; k >= j; k--)
                {
                        r[j-2] = k-1;
                        Cij(k - 1, j - 1,r,num,result);
                }
        }
}

2.4 測試結果

下面是測試結果:

3 排列演算法


4 參考

[1] http://www.cnblogs.com/shuaiwhu/archive/2012/04/27/2473788.html

相關推薦

C++排列組合演算法

轉載請註明出處1 介紹排列(Permutation)和組合(Combination)是兩個基礎的數學概念。計算排列與組合可以解決一些實際的工程問題,掌握排列組合計算的方法是十分重要的。目前,網上已經有一些計算排列組合的演算法,比如[1]。這裡我也給出一個組合計算方法。該計算方

C#實現排列組合演算法

數學中排列組合,排列P(N,R) 其實排列實現了,組合也就實現了組合C(N,R)就是P(N,R)/P(R,R) ,比較簡單的是遞迴演算法,但考慮到遞迴的效能,下面採用了2種非遞迴的方法,程式碼如下 using System; using System.Collections

C語言排列組合

排列組合:數學公式求解 #include<stdio.h> double Count(int n); int main() { int n,m; double Above,Below,x; double Count(int n); printf("

c#排列組合演算法

Combinatorics.cs程式碼清單   using System; using System.Collections; using System.Data;      &nbs

排列組合演算法總結(基於C++實現)

1.排列 全排列n! 1.1 遞迴法 設一組數p = {r1, r2, r3, … ,rn}, 全排列為perm(p),pn = p – {rn}。則perm(p) = r1perm(p1), r2perm(p2), r3perm(p3), … , r

c語言實現排列組合演算法問題

排列組合是演算法常用的基本工具,如何在c語言中實現排列組合呢?思路如下: 首先看遞迴實現,由於遞迴將問題逐級分解,因此相對比較容易理解,但是需要消耗大量的棧空間,如果執行緒棧空間不夠,那麼就執行不下去了,而且函式呼叫開銷也比較大。 (1) 全排列: 全排列表示把集合

c# C(m,n) 排列組合演算法

n從1到m的所有組合: static void Main() {     string[] arr = new string[] { "a", "b", "c", "d", "e" };     L

演算法基礎排列組合問題-全排列(Golang實現)

【排列組合問題】 一共N輛火車(0<N<10),每輛火車以數字1-9編號,要求以字典序排序輸出火車出站的序列號。 輸入: 包括N個正整數(0<N<10),範圍為1到9,數字之間用空格分割,字串首位不包含空格。 輸出: 輸出以字典

數據庫之排列組合

http sna bsp 查詢 inf sele where spa info 場景:表Team中就一個字段classname,有4條記錄,分別為a,b,c,d,表示共有4個班級。 需求:現在要組織足球比賽,要一條sql語句查詢出所有的兩兩的比賽組合。 也就是要得出這麽一個

C++ 泛型演算法

泛型演算法   泛型演算法大多數獨立於任何特定的容器,這些演算法是獨立的(或者稱“泛型的”),他們可以用於不同型別的容器和不同型別的元素。泛型演算法本身不會執行容器的操作,他們只會執行在迭代器之上,執行迭代器的操作。       泛型演算法基本包含在&

c語言排列組合還可以這樣求

本文主要講程式設計比賽中常用的排列組合。 首先,排列組合的公式是(其中P代表的就是A) 最普通的演算法就是按照公式求了,即分子算出來,分母算出來,然後相除,寫成程式碼為: int c( int m,int n ) { int a = 1,b = 1, c = 1; f

C/C++各種基本演算法實現小結(四)—— 圖及其遍歷

各種基本演算法實現小結(四)—— 圖及其遍歷 (均已測試通過) ==================================================================== 圖——深度優先和廣度優先演算法 無向圖

C/C++各種基本演算法實現小結(六)—— 查詢演算法

各種基本演算法實現小結(六)—— 查詢演算法 (均已測試通過) =================================================================== 1、簡單查詢 在一組無序數列中,查詢特定某個數值,並返回其位置

C/C++各種基本演算法實現小結(七)—— 常用演算法

各種基本演算法實現小結(七)—— 常用演算法 (均已測試通過) ====================================================================== 1、判斷素數 測試環境:VC 6.0

關於全排列組合演算法

全排列是將一組數按一定順序進行排列,如果這組數有n個,那麼全排列數為n!個。現以{1, 2, 3, 4, 5}為例說明如何編寫全排列的遞迴演算法。1、首先看最後兩個數4, 5。 它們的全排列為4 5和5 4, 即以4開頭的5的全排列和以5開頭的4的全排列。由於一個數的全排列就

C/C++各種基本演算法實現小結(二)—— 堆 棧

各種基本演算法實現小結(二)—— 堆 棧 (均已測試通過) ============================================================== 棧——陣列實現 測試環境:Win - TC

java排列組合演算法(M選N)

從M長度的容器中每次選取N個元素 舉例,從(a,b,c,d,e)中取兩個元素,則為(ab) (ac) (ad)(ae)(bc)(bd)(be)(cd)(ce)(de) import java.util.ArrayList; import java.uti

C/C++各種基本演算法實現小結(三)—— 樹與二叉樹

各種基本演算法實現小結(三)—— 樹與二叉樹 (均已測試通過) =================================================================== 二叉樹——先序 測試環境:VC 6.0 (C

java 高效率的排列組合演算法(java實現)

package BeanUtil; import java.util.ArrayList; import java.util.List; import com.work.core.exception.OurException; /** * 統計任三出現的最

排列組合演算法 java

排列組合問題,最簡潔有效的方法則是利用遞迴 一、無重複資料選K個組合: /* * 無重複資料組合--dfs解法   * data為資料 re為結果, curpo為當前位置,curlen為當前結果的長度 ,K為目標長度  *例如 data=“123456”  選3個字元組合,