经典算法之《八皇后》

  八皇后问题,是一个古老而著名的问题,是回溯算法的典型例题。该问题是十九世纪著名的数学家高斯1850年提出:

在8X8格的国际象棋上摆放八个皇后,使其不能互相攻击,即任意两个皇后都不能处于同一行、同一列或同一斜线上,问有多少种摆法。

  其实这个算法挺简单,但是久仰八皇后的大名一直没下手,其实就是一个dfs+回溯,记得给点染色和清除染色就ok,一共92种摆法,

自我感觉自己的代码还是挺简单的,而且觉得算法比百度百科里面还是要好那么一些,于是就果断贴上来了;temp[]数组用来存放每一种摆

法的状态,为8位的整数,每一位代表每一行所放置的列的位置。

  下面来分析一下算法吧:我们对每一个合适的点进行dfs,由于每一行只能放一个棋子,所以一旦有了合适的位置放置棋子就往下一行

摆放,同时把这个点标记为已经放棋子,这样在下面的dfs中就可以来判断存放下一颗棋子是否符合标准,如果符合则继续下一行,最后当row==8

时,回溯,同时消除上一个放置点的标记。这样的遍历便不重复。ps:在判断的时候可以适当优化,不过这个算法也已经很快

 1 //====================================================================
 2 //Name       :经典问题--八皇后
 3 //Author     :hxf
 4 //copyright  :http://www.cnblogs.com/Free-rein/
 5 //Description:
 6 //Data       :2012.8.19
 7 //========================================================================
 8 #include<iostream>
 9 #include<algorithm>
10 #include<stdio.h>
11 #include<math.h>
12 #include<string>
13 #include<cstring>
14 #include<vector>
15 #include<stack>
16 #include<queue>
17 #define MAXN 100050
18 #define inf 10100
19 using namespace std;
20 int map[10][10];
21 int ans=0;
22 int temp[100];//存放结果状态
23 void dfs(int row)
24 {
25     for(int j=1;j<=8;j++)
26     {
27         int s=0;//在下面的判断里若不符合要求则标记为1
28         for(int i=1;i<row;i++)
29         {
30             if(map[i][j]==1)
31                 s=1;
32             for(int k=1;k<=8;k++)
33                 if(((row-i==j-k)||(row-i==k-j))&&map[i][k]==1)
34                 {
35                     s=1;
36                     break;
37                 }
38         }
39         if(s==0&&row<8)//第row行第j列符合存放要求
40         {
41             map[row][j]=1;//标记颜色
42             dfs(row+1);//dfs下一行
43             map[row][j]=0;//dfs完毕,消除染色
44         }
45         if(s==0&&row==8)
46         {
47             int state=0;
48             for(int i=1;i<8;i++)
49             {
50                 for(int k=1;k<=8;k++)
51                 {
52                     if(map[i][k]==1)
53                         state=state+k;
54                 }
55                 state=state*10;
56             }
57             state=state+j;
58             ans++;//计数器+1
59             temp[ans]=state;
60             break;
61         }
62     }
63 }
64 int main()
65 {
66     memset(map,0,sizeof(map));
67     for(int j=1;j<=8;j++)
68     {
69         map[1][j]=1;
70         dfs(2);
71         map[1][j]=0;
72     }
73     printf("%d\n",ans);
74     while(1)
75     {
76         int n;
77         scanf("%d",&n);//输入n
78         printf("%d\n",temp[n]);//输出第n种状态
79     }
80     return 0;
81 }

  是不是代码完了就没事了呢?处在学习阶段果断不能这样(→_→) ...我们想想还有木有别的方法,建图的话那就差不多了,当然我们也可以不用染色,而用hash,在这里

一共也不过8^8种状态量,于是构建一个hash表来存放每一种状态,如果这种状态已经处理过了则可以直接跳过,应该也是可以得到答案的...

 

转载于:https://www.cnblogs.com/Free-rein/archive/2012/08/19/2646692.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值