八皇后问题

八皇后问题

是一个古老而著名的问题,是回溯算法的典型案例。该问题是国际西洋棋棋手马克斯·贝瑟尔于1848年提出:在8×8格的国际象棋上摆放八个皇后,使其不能互相攻击,即任意两个皇后都不能处于同一行、同一列或同一斜线上,问有多少种摆法。

以4皇后为例,如图所示,在图(a)中,第1行第1列上放置一个皇后,图(b)中确定第2行的可能放法,在尝试第1列、第2列由于相互攻击而放弃之后,确定在第3列放置可以继续,在图(c)中继续对第3行进行考察,发现将所有4列都尝试过了,也没有办法将皇后安排一个合适的位置,对第4行做任何的尝试都没有意义,这时产生回溯,结果是在图(d)中将第2行的皇后安排到第4列,然后第3行的暂时可以放在第2列,在图(e)中试着确定第4行的皇后,却发现无解再次回溯,只能够如图8.22(f)所示将第1行的皇后放到第2列,再经图(g)、(f)之后找到4皇后问题的一个解,那就是图(g)的(2, 4, 1, 3)。

搞清楚用回溯法求解的过程后,将关注什么样的解才是可行的?需要描述出任何两个皇后可以“互相攻击”这样的条件:
  (1)有两个皇后处在同一行
  (2)有两个皇后处在同一列
  (3)有两个皇后处在同一斜线
所以我们只需要判断不满足上述三个条件即可!

假设此时位置处于X,只要遍历(x-1,y-1)、(x-1,y)、(x-1,y+1)三个方向,只要能在等于 ” * ” 前找到等于 “ # ”,就说明此方向没有皇后。

#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
#include <stdlib.h>
#define N 8
char board[N + 2][N + 2];

typedef struct Pos
{
    int xos;
    int yos;
}pos_t;
pos_t pos[3] = {    //定义1个结构体,表示移动的位数(x-1,y-1)\(x-1,y)\(x-1,y+1)
    { -1, -1 },
    { -1, 0 }, 
    { -1, 1 } 
};

void Initboard()//初始化棋盘
{
    int i, j = 0;
    for (i = 1; i <= N; i++)
    {
        for (j = 1; j <= N; j++)
        {
            board[i][j] = ' ';
        }
    }
    for (i = 0; i <= N+1; i++)
    {
        board[0][i] = '#';
        board[i][N + 1] = '#';
        board[N + 1][i] = '#';
        board[i][0] = '#';
    }
}

void display()//显示棋盘
{
    int i, j = 0;
    for (i = 0; i < N + 2; i++)
    {
        printf("------------------------------\n");
        for (j = 0; j < N + 2; j++)
        {
            printf("%2c|", board[i][j]);
        }
        printf("\n");
    }
    printf("\n");
}

int check(int i, int j)//检查当前行是否可以放。返回0说明不能放;1能放
{
    int k = 0;
    int ret = 1;
    for (k = 0; k < 3; k++)
    {
        int nx = i;
        int ny = j;
        while (ret && (board[nx][ny] != '#'))
        {
            if (board[nx][ny] == '*')
                ret = 0;
            nx += pos[k].xos;
            ny += pos[k].yos;
        }
    }
    return ret;
}

void Find(int line)
{
    static int count = 0;
    if (line > N)
    {
        count++;
        printf("共有%d种情况\n", count);
        display();
    }
    else
    {
        int j = 0;
        for (j = 1; j <= N; j++)
        {
            if (check(line,j))
            {
                board[line][j] = '*';
                Find(line + 1);
                board[line][j] = ' ';// 下一行不能放,说明当前行的当前位置不合适 
            }
        }
    }
}

int main()
{
    Initboard();
    Find(1);
    system("pause");
    return 0;
}

这里写图片描述

回溯法

回溯法是一种通用的搜索算法,几乎可以用于求解任何可计算的问题。算法的执行过程就像是在迷宫中搜索一条通往出口的路线,总是沿着某一方向向前试探,若能走通,则继续向前进;如果走不通,则要做上标记,换一个方向再继续试探,直到得出问题的解,或者所有的可能都试探过为止。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值