指数枚举,排列枚举,组合枚举以及n皇后问题

指数形枚举:即集合中的元素,选或者不选两种状态,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 }

猜你喜欢

转载自www.cnblogs.com/1-0001/p/12222275.html
今日推荐