dfs 全排列演算法(含重複元素)
阿新 • • 發佈:2018-11-11
1、數的全排列
求數字 1 ~ n 的全排列,例如 1~3 的全排列,輸出 1 2 3, 1 3 2 , 2 1 3, 2 3 1, 3 1 2, 3 2 1
#include<bits/stdc++.h> using namespace std; #define runfile freopen("E:/Code/CB/Root/data.txt", "r", stdin) #define stopfile fclose(stdin) const int maxn = 100; int n,vis[maxn],perm[maxn];//標記陣列,全排列 void dfs(int step)//全排列,step 為當前選擇元素的數量 { if(step == n+1)//已經選滿 n 個數,得到全排列,深搜結束 { for(int i = 1; i <= n; i++) { cout<<perm[i]<<" "; } cout<<endl; } else { //從1~n個選中一個未被選中的元素,然後繼續深搜。深搜結束之後回溯 for(int i = 1; i <= n; i++) { if(!vis[i])//未被標記 { vis[i] =1;//標記 perm[step] = i;//記錄 dfs(step+1);//深搜下一步 vis[i] = 0;//回溯 } } } } int main() { // runfile; ios::sync_with_stdio(false); while(cin>>n) { memset(vis, 0, sizeof(vis)); dfs(1); } // stopfile; return 0; }
2、字元的全排列
#include<bits/stdc++.h> using namespace std; #define runfile freopen("E:/Code/CB/Root/data.txt", "r", stdin) #define stopfile fclose(stdin) const int maxn = 100; int n,vis[200];//標記陣列,全排列 char s[maxn],perm[maxn]; void dfs(int step)//全排列,step 為當前選擇元素的數量 { if(step == n+1)//已經選滿 n 個數,得到全排列,深搜結束 { for(int i = 1; i <= n; i++) { cout<<perm[i]<<" "; } cout<<endl; } else { //從1~n個選中一個未被選中的元素,然後繼續深搜。深搜結束之後回溯 for(int i = 0; i < n; i++) { int temp = (int)s[i];//注意此處與數字標記的不同 if(!vis[temp])//未被標記 { vis[temp] =1;//標記 perm[step] = s[i];//記錄 dfs(step+1);//深搜下一步 vis[temp] = 0;//回溯 } } } } int main() { // runfile; ios::sync_with_stdio(false); while(scanf("%d",&n) != EOF) { getchar(); for(int i = 0; i < n; i++) { scanf("%c",&s[i]); } getchar(); memset(vis, 0, sizeof(vis)); dfs(1); } // stopfile; return 0; }
3、含重複元素的全排列(首先要強制排序,然後再回溯的過程中記錄上一個值的位置,保證相同的元素不會進行互換)
#include<bits/stdc++.h> using namespace std; #define runfile freopen("E:/Code/CB/Root/data.txt", "r", stdin) #define stopfile fclose(stdin) const int maxn = 100; int n,vis[maxn],pre;//標記陣列,全排列 char s[maxn],perm[maxn]; void dfs(int step)//全排列,step 為當前選擇元素的數量 { if(step == n+1)//已經選滿 n 個數,得到全排列,深搜結束 { for(int i = 1; i <= n; i++) { cout<<perm[i]<<"*"; } cout<<endl; } else { //從1~n個選中一個未被選中的元素,然後繼續深搜。深搜結束之後回溯 int pre = -1;//記錄前一個選中的根節點 for(int i = 0; i < n; i++) { if(i == 0 || s[i] != s[pre]) { if(!vis[i])//未被標記 { vis[i] =1;//標記 perm[step] = s[i];//記錄--相當於兩個數交換的過程 dfs(step+1);//深搜下一步 vis[i] = 0;//回溯 pre = i;//記錄 pre } } } } } int main() { // runfile; ios::sync_with_stdio(false); while(scanf("%d",&n) != EOF) { getchar(); for(int i = 0; i < n; i++) { scanf("%c",&s[i]); } getchar(); sort(s, s+n);//先強制排序 memset(vis, 0, sizeof(vis)); dfs(1); } // stopfile; return 0; }