排列組合是組合學最基本的概念。所謂排列,就是指從給定個數的元素中取出指定個數的元素進行排序。組合則是指從給定個數的元素中僅僅取出指定個數的元素,不考慮排序。
詳細定義參考:
在各種演算法比賽,或面試題中經常會出現關於排列組合的演算法題,這裡總結幾種典型解法來給大家參考
如果是簡單的排列計數問題可以通過數學公式進行計算,但如果題目的是帶條件的計數問題,或者排列列舉問題,就可以使用遞迴加以解決
設集合a[1,2,3],全擺列集合a
[1 2 3] 1-》2得到2 1 3
[1 2 3] 1-》3得到3 2 1
[1 2 3] 2-》3得到1 3 2
由上面的例子我們可以得到全排的大體思路
1.選定乙個元素與其他元素交換位置
2.選定下乙個元素與剩下的交換位置
(每次交換元素位置錢之前要復原)
重複上述過程直到沒有元素可選
例:輸出0-9的全排列
/**
* 全排列0-9
* @author administrator
* */
public class main ;
//static int b = new int[10];
public static void main(string args)
static void f(int n)
system.out.println();
return;
} for(int i = n ; i < a.length ; i++);//選定乙個元素與其他元素交換位置
f(n+1);//選定下乙個元素與剩下的交換位置
;//下次交換之前復原
} }}
上面的就是典型的元素不重複的全排列問題,當列舉完成的時候同時也完成了計數,可以在出口處新增條件來解決類似剪郵票的問題,先暴力列舉所有情況,然後根據條件過濾結果
這裡的問題等價於在乙個元素不重複集合中隨機取n個元素,得到所有取數的可能性,我們把前n個元素依次與後面的元素交換,就可以等到所有可能的情況
類似的,元素不重複的部分排列問題也可以由遞迴解決
/**
* 從3個元素中,取兩個元素
* @author administrator
* */
public class main ;
//static int b = new int[10];
public static void main(string args)
static void f(int n)
system.out.println();
return;
} for(int i = n ; i < a.length ; i++);
f(n+1);
;} }
}
接下來是有重複元素的排列問題
設有m(m!=0)個蘋果,先要求取n(n!=0)個有多少種取法
利用公式 f(m,n) = f(m-1,n-1)+f(m-1,n)遞迴解決
ps:假設蘋果s被取出有f(m,n-1),假設蘋果s未被取出有f(m-1,n)
/**
* 元素不重複組合計數問題
* @author administrator
* */
public class main
static int f(int m,int n)
}
當元素不重複且固定的時候,可以用多重迴圈列舉出來,可當固定時就需要用遞迴了。
例:從abcde選取三個字元
/**
* 元素不重複組合列舉問題
* @author administrator
* */
public class main }
static listf(string s , int n)
//相似性
for(int i = 0 ; i < s.length() ; i++)
}return l;
}}
例:選取aaabbc中的任意三個字母
思路一:假設字串不重複,取出所有組合,用set集合去重
思路二:用int陣列儲存abc可能存在的最大次數,在遞迴中將最大可能和要取的數中進行比較,利用遞迴得到abc出現的次數所有可能儲存到陣列中,最後利用work()輸出
/**
* 元素重複組合列舉問題
* 選取aaabbc中的任意三個字母
* @author administrator
* */
public class main ;
int x = new int[data.length];
f(data,x,0,3);
} /**
* @param data : 字母允許出現的最大次數
* @param x : 結果集中字母出現的次數
* @param k : 當前位置
* @param goal : 當前需要取的字母個數
*/static void f(int data , int x , int k , int goal)
for(int i = 0 ; i <=math.min(data[k], goal);i++)
x[k] = 0;//回溯
} /**
* * @param x : x陣列中記錄了每乙個字母出現的次數
*/static void work(int x)
} system.out.println();
}}
例題:派遣問題 演算法 遞迴思想解決排列組合問題
演算法 遞迴思想解決排列組合問題 直接上 void astring m char str,char pbegin void astring char str 提供的公共介面函式 void cstring m char pstr,int m,vector result result.push back...
C C 排列組合問題(遞迴)
1 問題描述 乙個mxn的矩形,從左下角走到右上角有多少種走法。include include using namespace std void luxian int alen,int blen,char p 100 int ai,int bi,int num const int alen 5 co...
遞迴實現排列組合問題
臨近acm大賽了,博主正在複習遞迴,畢竟博主是乙個菜鳥,對遞迴總是有太多的疑問,所以蒐羅了一些資料集中細談一下用遞迴處理的排列組合問題 題目 用遞迴演算法輸出cn m 從m中取n個數 的每一次的值 如下 include using namespace std int n,m,n n,m為題中的n,m...