N皇后问题(dfs深搜与数论规律的使用)

这是一道深搜题目!问题的关键是在剪枝。

下面我们对问题进行分析:

1.一行只能放一个皇后,所以我们一旦确定此处可以放皇后,那么该行就只能放一个皇后,下面的就不要再搜了。

2.每一列只能放一个皇后,所以我们下次搜索就不要再搜已经放过的皇后了。

3.斜的45°线也只能放一个。

综上如何才能最快速的确定一列和45°是否用过这个是个关键步骤,一旦此步骤确定我们就可以很快的进行搜索了。

我们用三个数组来保存他的每一个状态及(三个方向 ↖ ↑ ↗)(行,不用考虑,因为每次都是向下递归,每次都是新的一行,无需考虑冲突问题)

但是如果我们保存↑(每一列方向上的皇后)是非常容易保存的 但是保存( 这两个方向上的状态就不容易了↖ ↗)

 

再分析,在这个(↖)方向上的数据的行和列有什么特点

 0  1  2  3   4

-1  0  1  2  3

-2 -1  0  1  2

-3 -2 -1  0  1

-4 -3 -2 -1  0 

将此表列出我们就应该知道在(↖)方向上的数据的行和列的特点了,及   在 (↖)方向上  列 - 行 的差是相等的。

假如我们用数组保存负数肯定是不行的, 所以我们要加上 n,让他变为非负.

 

再分析,在这个( ↗)方向上的数据的行和列有什么特点

0 1 2 3 4

1 2 3 4 5

2 3 4 5 6

3 4 5 6 7

将此表列出我们就应该知道在(↗)方向上的数据的行和列的特点了,及   在 (↗)方向上  列 + 行 的和是相等的。

知道数据怎么处理就可以解决问题了。

下面附上参考代码:

n=13;//73711  n=14;   //365595到了15以上数值进行爆炸性增长呢!!

#include<iostream>
#include<cstring>
#include<cmath>
#include<stdio.h>
using namespace std;
int vis[3][50], P[15];//三个方向 ↖↑↗在此三个方向都不能有皇后
int n, sum;

void  DFS(int row);

int main()
{
    for(n = 1; n <= 10; n++)   //先打表不然会超时的
    {
        memset(vis,0,sizeof(vis));
        sum = 0;
        DFS(1);
        P[n] = sum;
    }
    while(scanf("%d",&n), n)
    {
        printf("%d\n",P[n]);
    }
    return 0;
}


void  DFS(int row)//每次都下一行,不用担心行问题
{
    int i;
    if(row == n + 1)//已经够n行了
    {
        sum ++;
        return ;
    }
    for(i = 1; i <= n; i++)
    {
        if(vis[0][row-i+n] == 0 && vis[1][i] == 0 && vis[2][row+i] == 0)
        {//不会回溯的同学要好好看看学习学习
            vis[0][row-i+n] = vis[1][i] = vis[2][row+i] = 1;//变值
            DFS(row + 1);//深搜
            vis[0][row-i+n] = vis[1][i] = vis[2][row+i] = 0;//回溯
        }
    }
}

https://www.cnblogs.com/chenchengxun/p/3759278.html

#include<iostream>
#include<cstring>
#include<cmath>
#include<stdio.h>
#include<windows.h>
using namespace std;
int vis[3][50], P[26];//三个方向 ↖↑↗在此三个方向都不能有皇后,空间大小也要n*n的大小
int n, sum;
void  DFS(int row);

int main()
{
    for(n = 1; n <=10 ; n++)   //先打表不然会超时的
    {
        //cout<<"a"<<endl;
        //n=13;//73711
        //n=14;//365595
        memset(vis,0,sizeof(vis));
        sum = 0;
        DFS(1);  //从第一行开始
        P[n] = sum;
        //getchar();
    }
    while(scanf("%d",&n), n)
    {
        printf("%d\n",P[n]);
    }
    return 0;
}


void  DFS(int row)//每次都下一行,不用担心行问题
{
    int i;
    if(row == n + 1)//已经够n行了
    {

        sum ++;
        return ;
    }
    for(i = 1; i <= n; i++)
    {
        if(vis[0][row-i+n] == 0 && vis[1][i] == 0 && vis[2][row+i] == 0)
        {
            vis[0][row-i+n] = vis[1][i] = vis[2][row+i] = 1;//变值
            DFS(row + 1);//深搜
            vis[0][row-i+n] = vis[1][i] = vis[2][row+i] = 0;//回溯
        }
    }
}

小白的代码记录

#include <iostream>
#include <algorithm>
#include <cstdlib>
#include <cmath>
#include <cstring>
#include <string>
#include <cstdio>
#include <deque>
#include <vector>
using namespace std;


int vix[15];
int viy[15];
int dui1;
int dui2;
int sum;
int num;

bool judge(int x,int y);
void dfs(int x,int y);
void in(int x,int y)
{
    vix[x]=1;
    viy[y]=1;
    if( x==y )
    {
        dui1=1;
    }
    if(x+y==num+1)
    {
        dui2=1;
    }
}
void on(int x,int y)
{
    vix[x]=0;
    viy[y]=0;
    if( x==y )
    {
        dui1=0;
    }
    if(x+y==num+1)
    {
        dui2=0;
    }
}



int main()
{

    while(cin>>num)
    {
        if(num==0)
            break;
        if(num==1)
        {
            cout<<"1"<<endl;
            continue;
        }
        if(num==2)
        {
            cout<<"0"<<endl;
            continue;
        }
       
        sum=dui1=dui2=0;
        memset(vix,0,sizeof(vix));
        memset(viy,0,sizeof(viy));

        for(int i=1; i<=num; i++)
        {
            memset(vix,0,sizeof(vix));
            memset(viy,0,sizeof(viy));
            dui1=dui2=0;
            in(1,i);
            dfs(1,i);
        }
        cout<<sum<<endl;

    }
    return 0;
}

void dfs(int x,int y)
{
    cout<<x<<" "<<y<<endl;
    if( x==num )
    {
        sum++;
        cout<<sum<<endl;
        return;
    }

    for(int i=1; i<=num; i++)
    {
        if(judge(x+1,i) && x+1<=num)
        {
            in(x+1,i);
            dfs(x+1,i);
            on(x+1,i);
        }

    }
    return;
}


bool judge(int x,int y)
{
    if(vix[x]==1)
    {
        return false;
    }
    if(viy[y]==1)
    {
        return false;
    }
    if(x==y && dui1==1)
    {
        return false;
    }
    if(x+y==num+1 && dui2==1)
    {
        return false;
    }
    else
        return true;
}

 

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值