回溯法是一種深度優先搜尋空間樹的演算法,演算法基本分成兩個部分試探部分和回溯部分,試探部分當滿足除規模外的全部條件時擴大規模,回溯部分回溯條件有兩個,當問題不是合法解和求完乙個解要求下乙個解的時候都要回溯。典型問題就是求組合數的問題。一般的遞迴在呼叫完了自身之後不會有動作了,而回溯不同,他在呼叫完了自身還是有動作的,一般是個迴圈,在迴圈中有可能不停的呼叫自身。
對於全排列問題,用遞迴演算法相對比較簡單,但是效率比較低,效率低的原因是因為要多次呼叫自己,呼叫函式是要開銷的,而且自己呼叫自己的過程中會產生大量的區域性變數,引數,返回位址都會壓在棧中,棧的空間大效率也會降低。組排列問題一般用回溯法來解決,與n皇后問題相類似。
全排列是將一組數按一定順序進行排列,如果這組數有n個,那麼全排列數為n!個。現以為例說明如何編寫全排列的遞迴演算法。
1、首先看最後兩個數4, 5。 它們的全排列為4 5和5 4, 即以4開頭的5的全排列和以5開頭的4的全排列。由於乙個數的全排列就是其本身(遞迴終止條件key),從而得到以上結果。
2、再看後三個數3, 4, 5。它們的全排列為3 4 5、3 5 4、 4 3 5、 4 5 3、 5 3 4、 5 4 3 六組數。即以3開頭的和4,5的全排列的組合、以4開頭的和3,5的全排列的組合和以5開頭的和3,4的全排列的組合.從而可以推斷,設一組數p = , 全排列為perm(p)。因此perm(p) = r1perm(p1), r2perm(p2), r3perm(p3), ... , rnperm(pn)。當n = 1時perm(p} = r1。為了更容易理解,將整組數中的所有的數分別與第乙個數交換,這樣就總是在處理後n-1個數的全排列。遞迴的時候每個函式多次的呼叫自身。
#include #include using namespace std;
int n = 0;
void swap(int *a, int *b) //陣列交換的是位址
void perm(int list, int k, int m)
else
} } int main()
;
perm(list, 0, 4); //傳遞的是陣列下表的
printf("total:%d\n", n);
return 0;
}
下面是組合問題:求乙個字串的所有組合。
假設我們想在長度為n的字串中求m個字元的組合。我們先從頭掃瞄字串的第乙個字元。針對第乙個字元,我們有兩種選擇:一是把這個字元放到組合中去,接下來我們需要在剩下的n-1個字元中選取m-1個字元;而是不把這個字元放到組合中去,接下來我們需要在剩下的n-1個字元中選擇m個字元。這兩種選擇都很容易用遞迴實現。
#include #include using namespace std;
void combination(char *str);
void combination(char *str, int number, vector&result);
int main()
void combination(char *str)
void combination(char *str, int number, vector&result)
if(*str == '\0')
return;
result.push_back(*str);
combination(str+1, number-1, result);
result.pop_back();
combination(str+1, number, result);
}
參考
排列and組合問題
1.全排列問題,如 字串abcdef的所有排列問題或者數字1234的全排列問題 case 1 普通情況 leetcode 46題 for int i k icase 2 特殊情況,含有重複的數字 2.組合問題,如長度為n的字串中取出m個字元的組合,leetcode 77題 給定兩個整數 n 和 k,...
排列和組合
排列組合計算公式 排列a n,m n n 1 n m 1 n!n m n為下標,m為上標,以下同 組合c n,m a n,m a m,m n!m!n m 問題 從1到n 包含 中選出m n個數,在下列情況下,有多少種組合?限制條件 1 無限制 2 各位數字公升序排列 3 不能有重複數字 4 各位數字...
排列和組合
組合 n取k的組合數 defcombination n int k int res deftraceback temp list index int if len temp k else for i in range index,n 1 traceback temp,i 1 temp.pop tra...