回溯法之遞歸回溯和迭代回溯
阿新 • • 發佈:2019-01-07
/* 設R={r1,r2,...rn}是要進行排列的n個元素.Ri=R-{ri}.集合X中元素的全排列記為 Perm(X).(ri)Perm(X)表示在全排列Perm(X)的每一個排列前加上字首ri得到的排列 R的全排列可歸納定義如下: 當n=1時,Perm(R)=(r),其中r是集合R中唯一的元素; 當r>1時,Perm(R)由(r1)Perm(r1),(r2)Perm(r2).....(rn)Perm(rn)構成. 依此遞迴定義,Perm(R)的遞迴演算法如下: */ #include <iostream> #include <algorithm> #include <vector> using namespace std; int cnt = 0; void Perm(int list[],int k,int m){ if(k == m){ cnt++; cout<<"cnt = "<<cnt<<endl; for(int i = 0 ; i <= m ; i++){ cout<<list[i]<<" "; } cout<<endl; } else{ for(int i = k ; i <= m; i++){ swap(list[k],list[i]); Perm(list,k+1,m); swap(list[k],list[i]); } } } /* 迭代實現,演算法思想: 該問題的解空間是一棵排列樹(可以看作子集樹剪去了很多枝) 因此採用回溯法對解空間樹進行搜尋,得到想要的結果 對於長度為N的序列,可以看作深度為N的一棵樹,依次對每一層搜尋其子樹節點 該例子中,第一層可選的子樹節點有N個,第二層有N-1個知道最後一層葉子節點只有一個 是一棵典型的排列樹 */ void Perm_iterative(int list[],int n){ int t = 0; vector<int> p = {-1,-1,-1,-1,-1};//p[i]表示在第i個位置(樹第i層)排list[p[i]],list的第p[i]個元素 //set<int> bkt[n+1]; while(t >= 0){ int k = p[t]; while(find(p.begin(),p.end(),k) != p.end()) k++; if( k > n || t > n){//返回上一層節點時,清空子樹狀態 for(int i = t; i <= n; ++i) p[i] = -1; t--; continue; } p[t] = k; if( t >= n){//找到一個排列 cnt++; cout<<"cnt = "<<cnt<<endl; for(int i = 0 ; i <= n ; i++){ cout<<list[p[i]]<<" "; } cout<<endl; } else{ //cout<<"that"<<endl; t++; } } return; } int main(){ int x[] = {1,2,3,4,5}; cout<<"this is a test"<<endl; //Perm(x,0,4); Perm_iterative(x,4); }