指数形枚举:即集合中的元素,选或者不选两种状态,0和1, 即集合的所有子集。例如{1, 2}集合中的子集有{},{1},{2},{1, 2}。
运用深搜进行指数型枚举,在挑选数字时,用一个状态state记录挑选的数字,从前往后枚举,当枚举到最后一位的后一位
的时候,输出。
1 #include <iostream> 2 3 using namespace std; 4 5 const int N = 20; 6 7 int a[N]; 8 int n; 9 10 void dfs(int step, int state) 11 { 12 if(step == n)//当枚举到最后一位的后一位,即代表前面n位都尝试过,输出 13 { 14 for(int i = 0 ; i < n ; i ++)//遍历状态 15 if(state >> i & 1)//如果该数字的状态是选中就输出 16 cout << i + 1 << " ";//由于step从0开始,数字从1开始,要加上偏移量 17 cout << endl; 18 return;//输出完务必return 19 } 20 dfs(step + 1, state);//对下一个数做决定,不选当前数 21 dfs(step + 1, 1 << step | state);//对下一个数做决定,选当前数 22 } 23 24 int main(){ 25 cin >> n; 26 27 dfs(0, 0); 28 29 return 0; 30 }
组合型枚举:组合型枚举一般为从n个数中选择m个数,m<=n。例如{1, 2, 3}中选2个数,有{1, 2},{1, 3},{2, 3}。
依旧是运用深搜枚举,同样用一个state记录被选数字,与指数型枚举不同的是:1.必须优先选择当前数字。2.当已经到最后一个数字的后一位时还没有选择满m个数字,要return。
1 #include <iostream> 2 3 using namespace std; 4 5 const int N = 25; 6 7 int a[N]; 8 int n, m; 9 10 void dfs(int step, int state, int cnt) 11 { 12 if(cnt == m)//当选满m个数字,输出数字 13 { 14 for(int i = 0 ; i < n ; i ++) 15 if(state >> i & 1) 16 cout << i + 1 << " "; 17 cout << endl; 18 return;//记得return 19 } 20 if(step == n)return;//如果到最后一位后一位还未满m个数字,return 21 dfs(step + 1, 1 << step | state, cnt + 1);//优先选择当前数字的方案 22 dfs(step + 1, state, cnt);//不选择当前数字的方案 23 24 } 25 26 int main(){ 27 cin >> n >> m; 28 29 dfs(0, 0, 0); 30 return 0; 31 }
排列型枚举:即{1, 2}与{2, 1}是不同的排列方案。
用深搜进行搜索,用一个st数组标记被选数字,用a数组存储被选数字。
1 #include <iostream> 2 3 using namespace std; 4 5 const int N = 10; 6 7 int a[N]; 8 bool st[N]; 9 int n; 10 11 void dfs(int step) 12 { 13 if(step == n) 14 { 15 for(int i = 0 ; i < n ; i ++) 16 cout << a[i] << " "; 17 cout << endl; 18 return; 19 } 20 for(int i = 1 ; i <= n ; i ++)//枚举1-9的数字 21 if(!st[i])//如果没有用过 22 { 23 a[step] = i;//将该数组存储到a数组内 24 st[i] = true;//标记该数字已经选过 25 dfs(step + 1);//进行下一步 26 st[i] = false;//回溯 27 } 28 } 29 30 int main(){ 31 cin >> n; 32 33 dfs(0); 34 35 return 0; 36 }
n-皇后问题:n-皇后问题是指将 n 个皇后放在 n∗n 的国际象棋棋盘上,使得皇后不能相互攻击到,即任意两个皇后都不能处于同一行、同一列或同一斜线上。
我们使用深搜,用step代表一次步骤,即代表一行,对于每一行,枚举每一列,判断在该位置上的竖直方向,两个斜边方向上是否有皇后,没有就放下。
判断竖线上是否有皇后用一个st数组即可,对于斜边,我们知道,对于处在同一条斜边上的(列数-行数)和 (列数+ 行数)的数值是相同的。
例如对于(列数-行数)的值如是。
1 #include <iostream> 2 3 using namespace std; 4 5 char g[20][20]; 6 bool st[20], a[20], b[20]; 7 int n; 8 9 void dfs(int step) 10 { 11 if(step == n) 12 { 13 for(int i = 0 ; i < n ; i ++)cout << g[i] << endl; 14 puts(" "); 15 return; 16 } 17 for(int i = 0 ; i < n ; i ++) 18 if(!st[i] && !a[i + step] && !b[i - step + n])//竖直方向和两斜边都没有皇后可以攻击到 19 { 20 g[step][i] = 'Q';//放下 21 st[i] = a[i + step] = b[i - step + n] = true; 22 dfs(step + 1); 23 g[step][i] = '.';//回溯 24 st[i] = a[i + step] = b[i - step + n] = false; 25 } 26 } 27 28 int main(){ 29 cin >> n; 30 for(int i = 0 ; i < n ; i ++) 31 for(int j = 0 ; j < n ; j ++)g[i][j] = '.'; 32 33 dfs(0); 34 35 return 0; 36 }