目錄
0.回溯法
回溯法與樹的遍歷:
程序設計中,有一類求一組解、求全部解或求最優解的問題,例如八皇后問題,
不是根據某種確定的計算法則,而是利用試探和回溯(Backtracking)的搜索技術來求解的。
回溯法也是設計遞歸過程的一種重要方法,其求解過程實質上是一個先序遍歷一棵
“狀態樹”的過程,只是這棵樹不是遍歷前就預先建立好的,而是隱含在遍歷過程中建立起來的。
1.問題
1.1求集合的冪集
集合A的冪集是由集合A的所有子集所組成的集合。
如A={1,2,3}
則A的密集PowerSet(A)={{1,2,3},{1,2},{1,3},{1},{2,3},{2},{3},{}}
求n個元素的集合的冪集。
求冪集PowerSet(A)的過程可以看成是依次對集合A中的元素進行“取”或“舍”的過程。
可以得到一棵二叉狀態樹:
{}
/ \
{1} {}
/ \ / \
{1,2} {1} {2} {}
/ \ / \ / \ / \
{1,2,3} {1,2} {1,3} {1} {2,3} {2} {3} {}
左分支代表“取”,右分支代表“舍”
1.2在一個集合中求組合
如A={1,2,3}
組合:在集合A中選取2個元素的組合有{1,2}、{1,3}、{2,3}
2.求冪集
#include<iostream>
#include<vector>
using namespace std;
vector<vector<int> > PowerSet;
/*
函數名:GetPowerSet
參數:
集合A
B爲A的冪集中的一個集合元素
i:向量A的下標,初始調用該函數時i=0
i=0,1,...,A.size()-1
*/
void GetPowerSet(vector<int> A, vector<int>& B, int i)
{
if (i >= A.size())
{
cout << "{";
for (auto x : B)
{
cout << x << ",";
}
cout << "}"<< endl;
PowerSet.push_back(B);
return;
}
else
{
int x = A[i];
B.push_back(x); //取該元素
GetPowerSet(A, B, i + 1); //取該元素的遞歸分支
B.pop_back(); //捨棄該元素
GetPowerSet(A, B, i + 1); //捨棄該元素的遞歸分支
}
}
int main()
{
vector<int> mySet;
vector<int> temp;
mySet.push_back(1);
mySet.push_back(2);
mySet.push_back(3);
GetPowerSet(mySet, temp, 0);
return 0;
}
輸出:
{1,2,3,}
{1,2,}
{1,3,}
{1,}
{2,3,}
{2,}
{3,}
{}
如果要求A中選2個元素的組合,則過濾A的冪集中元素個數爲2的即可。
3.參考
編程珠璣:求集合的組合與排列
位圖(0、1:舍、取)代表每個元素的取捨狀態:
比如上面的集合A的冪集:
000 ——> {}
001 ——> {1}
010 ——> {2}
011 ——> {2,1}
100 ——> {3}
101 ——> {3,1}
110 ——> {3,2}
111 ——>{3,2,1}
對於8個冪集元素的狀態。
參考:
https://www.cnblogs.com/blastbao/p/8306810.html