八皇后问题

22 篇文章 1 订阅
14 篇文章 0 订阅

在回溯法的运用中的经典案例,问题如下:
在棋盘上放置8个皇后,使得他们互相不能攻击到,此时每个皇后的攻击范围为同行同列和同对角线(主副对角线),要求找出所有解。
一个解如图
这是问题的一个解
我们使用递归枚举(也就是回溯法)来求解这个问题。
先分析下问题的规模:从0行开始到第7行每行都必须有一个皇后,所以固定了行之后,按列来算就是全排列问题,排列数是8!=40320个,枚举数是不会超过它的,所以问题规模不大,可以进行回溯求解。

下面给出直观的代码
递归遍历每行,每层递归通过循环遍历每列,判断是否和之前的皇后位置冲突,未冲突则记录下来,冲突则返回上一层递归点。

#include <string.h>
#include <iostream>
using namespace std;
int t = 0;
int Arr[10] = { 0 };//用来存每行的皇后放在哪列上
//第一个参数是递归的行数,第二个参数的代表皇后的个数
void problem_queen(int cur, int n)
{
    if (cur == n)//边界条件,递归完所有的行则退出
    {
        t++;
        //打印出所有解
        //for (int i = 0; i < n; i++)
        //{
        //      i == n-1 ? printf("(%d,%d)", i, Arr[i]):printf("(%d,%d) ", i, Arr[i]);
        //}
        //printf("\n");
        //return;
    }
    for (int i = 0; i<n; i++)//遍历n列
    {
        int ok = 1;
        Arr[cur] = i;//将列数放入数组进行判断与前面皇后是否冲突
        for (int j = 0; j<cur; j++)
        {
            if (Arr[cur] == Arr[j] || Arr[cur] + cur == Arr[j] + j || Arr[cur] - cur == Arr[j] - j) //判断纵行,主对角线和副对角线
            {
                ok = 0;
                break;
            }
        }
        if (ok)problem_queen(cur + 1, n);
    }
}
int main()
{
    memset(Arr, 0, sizeof(Arr));
    problem_queen(0, 8);
    return 0;
}

这里说明一下主对角线和副对角线是否冲突的判断,下图的横向是x(0 , 7)
纵向是y(0,7)
如图1
这里写图片描述
图1 格子中的值(x-y)标识了主对角线冲突,值相同即冲突

如图2,标记了副对角线的冲突
这里写图片描述
图2 格子中的值(x+y)

在上面的代码中,判断当前的皇后是否前面的皇后有冲突的循环可以去掉,由此可以优化代码的效率

#include <string.h>
#include <iostream>
using namespace std;
int vis[3][20];//判断纵向、主对角线、副对角线是否冲突,因为是逐行比较,所以横向肯定不会冲突
int t = 0;
int pos[10][10];
void search(int cur,int n)
{
    if (cur == n)
    {
        t++; 
        for (int i = 0; i < n; i++)
        {
            for (int j = 0; j < n; j++)
            if (pos[i][j])
                j == n-1 ? printf("(%d,%d)", i, j):printf("(%d,%d) ", i, j);
        }
        printf("\n");
        return;
    }

    for (int i = 0; i < n; i++)
    {
        if (!vis[0][i] && !vis[1][i + cur] && !vis[2][cur - i + n])//在判断y-x时存的值有负值,所以这里对索引下标做个平移加个n
        {
            vis[0][i] = vis[1][i + cur] = vis[2][cur - i + n] = 1;
            pos[cur][i] = 1;
            search(cur + 1, n);
            vis[0][i] = vis[1][i + cur] = vis[2][cur - i + n] = 0;//在退出这一层的递归之前要清除辅助变量记录的值,否则会影响下一次递归到该结点
            pos[cur][i] = 0;
        }
    }
}
int main()
{
    memset(vis, 0, sizeof(vis));
    memset(pos, 0, sizeof(pos));
    search(0, 8);
    return 0;
}

以上就是八皇后问题的解法,注意的是,在使用回溯法时,使用到的辅助用的全局变量,在函数出口之前要将辅助变量及时恢复原状,以免影响下一次的递归,有多个出口时更要注意这个问题。


转载请注明出处:http://blog.csdn.net/gyh_420/article/details/75194011

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值