上一篇說了使用位運算來進行子集輸出,這裏使用回溯的方法來進行排序。
回溯的思想,個人理解就是:數組
把解的全部狀況轉換爲樹或者圖,而後用深度優先的原則來對全部的狀況進行遍歷解析。函數
固然,由於問題中會包涵這各類各樣的限制條件,咱們能夠用這些限制條件去減小遍歷的分支。
其實,比較著名的就是0-1揹包問題,這個揹包問題以後再說,這裏先看排列組合。code
假設咱們的數組爲[6,7,8],依然使用0來表示當前數字不存在,用1來表示當前數字存在,咱們就能夠畫出這樣一個樹:
blog
這裏使用遞歸來生成對應的flag標記,重點是backtrack函數:排序
#include <stdio.h> int x[] = {6,7,8}; // 須要排列的數組 int y[] = {0,0,0}; // 存放flag標記 int level = 3; // 有3個數字須要進行排列,對應的就須要排3層 void show() { for (int i=0; i<level; i++) { printf("flag : %d ", y[i]); } printf("\n"); } void backtrack (int t) { if (t == level) // 當遍歷深度等於level的時候,說明遍歷完成,獲得一組完整的flag標記 show(); else for (int i=0;i<=1;i++) // 這裏先生成0標記,再生成1標記 { y[t]=i; // 記錄當前層是否存在,0存在,1不存在 backtrack(t+1); // 遞歸遍歷下一層,這裏能夠根據題目限制來判斷是否須要繼續下一層的遍歷,能夠減小遍歷次數 } } int main(void) { backtrack(0); return 0; } 輸出結果爲: 0 0 0 0 0 1 0 1 0 0 1 1 1 0 0 1 0 1 1 1 0 1 1 1
回溯的基本就那麼一個思想,那限制條件怎麼用呢?
好比,我有10元錢,這裏有三個物品,價格分別是8元,5元,2元,10元,
問,這10元錢能夠有哪些買法?
這裏存在的一個限制就是:總數不能超過10。遞歸
#include <stdio.h> #define TOTAL 10 // 總數最多爲10 int x[] = {8,5,2,10}; // 價格 int y[] = {0,0,0,0}; int level = 4; void show() { int n=0; for (int i=0; i<level; i++) // 計算總價格是否超過10 { n += y[i] * x[i]; } if (TOTAL < n) { return; } for (int i=0; i<level; i++) // 這裏直接打印符合條件的價格 { printf("%d ", y[i]*x[i]); } printf("\n"); } void backtrack (int t) { if (t == level) show(); else for (int i=0;i<=1;i++) { y[t]=i; int n = 0; for (int j=0; j<t; j++) // 這裏先計算一下當前價格是多少 { n = y[j] * x[j]; } if (TOTAL > n) // 若是當前價格已經超了,就不須要再遞歸下一層(由於不論下一層是否存在,總價格必然會超),不然繼續遞歸 backtrack(t+1); } } int main() { backtrack(0); return 0; } 結果爲: 0 0 0 0 0 0 0 10 0 0 2 0 0 5 0 0 0 5 2 0 8 0 0 0 8 0 2 0