八皇后问题解题报告(dfs

这里是代码传送门

所谓八皇后问题,一开始接触,上学期舍友提及的,但是因为各种原因,水平不够,并没有关心,偶然之间,再次遇见,便进行的尝试(棋盘是0-7的,不是1-8的...开始打弄错了)

所谓八皇后问题,就是在8X8的棋盘上,求如何让可以往八个方向直走的皇后不互相攻击的摆放方法的解;
很显然,我的第一想法是用深搜剪枝(书上说是 回朔法 )
如何实现呢?我的想法是,先预定让每个皇后占一行,然后暴力搜索皇后所在列的情况,然后递归剪掉不满足的情况;

代码如下


#include<cstdio>
#include<queue>
#include<stack>
#include<string>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<iomanip>
#include<algorithm>
#include<iostream>
#define PI acos(-1)
#define ull unsigned __int64
#define Min(a,b) ((a>b)?b:a)
#define Max(a,b) ((a>b)?a:b)
#define INF 1000000007
using namespace std;
bool v[8]={0};//用来记忆
int node[8];//记录不同行的皇后所在的列
int coun=0;//统计一共解法
void dfs(int t)
{   
    if(t==8)//如果能达到8行,说明是满足条件的,不然会被剪枝
    {
        for(int i=0;i<8;i++) printf("(%d,%d) ",i,node[i]);
        printf("\n");
        coun++;
        return ;
     }
    for(int i=0;i<8;i++)//遍历
    {
        if(!v[i])//皇后的列数不能相同
        {
            int flag=true;//判断斜线
            for(int j=0;j<t;j++)
            {
                if(node[j]==i-(t-j)||node[j]==i+(t-j))
                //遍历前面已经给出的皇后是否在同一斜线位置,前面一个是k=-1的斜线,后面是k=1的斜线
                {
                    flag=false;//如果在同一斜线,则不能满足条件
                    break;
                }
             } 
             if(flag)//满足条件
             {
                node[t]=i;
                v[i]=1;
                dfs(t+1);
                v[i]=0;//这一步很重要
             }
            
        }
        
    }
    return ;
 }
 int main()
 {
    dfs(0);
    printf("count=%d\n",coun);
  } 

最终结果给出了92种情况,与网上无差。
之后参考了《挑战程序设计》p193页,发现思想与第一种方法无差
但是,他给出了另外一种更高效的解法。
定义的bool类型为二维的 bool vis[3][18],可以更加高效的实现算法:

改进版代码如下:

#include<cstdio>
#include<queue>
#include<stack>
#include<string>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<iomanip>
#include<algorithm>
#include<iostream>
#define PI acos(-1)
#define ull unsigned __int64
#define Min(a,b) ((a>b)?b:a)
#define Max(a,b) ((a>b)?a:b)
#define INF 1000000007
using namespace std;
bool vis[3][18]={0}; 
int node[8];
int coun=0;
void dfs(int t)
{   
    if(t==8)
    {
        printf("(%d,%d)",0,node[0]);
        for(int i=1;i<8;i++) printf("   (%d,%d)",i,node[i]);
        printf("\n");
        coun++;
        return ;
     }
    for(int i=0;i<8;i++)
    {
        if(!vis[0][i]&&!vis[1][i+t]&&!vis[2][t-i+8])
//V[0][i]表示记忆,vis[1][i]表示左下右上的斜线,vis[2][i]表现左上右下 
        {
                vis[0][i]=vis[1][i+t]=vis[2][t-i+8]=1;                                                   
                node[t]=i;
                dfs(t+1);
                vis[0][i]=vis[1][i+t]=vis[2][t-i+8]=0;
            
        }
        
    }
    return ;
 }
 int main()
 {
    dfs(0);
    printf("count=%d\n",coun);
  } 

只用了一层循环,这告诉了我们一点:

学好数学是很重要的

转载于:https://www.cnblogs.com/Anani-leaf/p/5219820.html

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值