回溯法解决八皇后问题

 

八皇后问题,是一个古老而著名的问题,是回溯算法的典型案例。该问题是国际西洋棋棋手马克斯·贝瑟尔于1848年提出:在8×8格的国际象棋上摆放八个皇后,使其不能互相攻击,即任意两个皇后都不能处于同一行、同一列或同一斜线上,问有多少种摆法。 高斯认为有76种方案。1854年在柏林的象棋杂志上不同的作者发表了40种不同的解,后来有人用图论的方法解出92种结果。计算机发明后,有多种计算机语言可以解决此问题。

回溯算法实际上一个类似枚举的搜索尝试过程,主要是在搜索尝试过程中寻找问题的解,当发现已不满足求解条件时,就“回溯”返回,尝试别的路径。回溯法是一种选优搜索法,按选优条件向前搜索,以达到目标。但当探索到某一步时,发现原先选择并不优或达不到目标,就退回一步重新选择,这种走不通就退回再走的技术为回溯法,而满足回溯条件的某个状态的点称为“回溯点”。许多复杂的,规模较大的问题都可以使用回溯法,有“通用解题方法”的美称。

回溯算法也叫试探法,它是一种系统地搜索问题的解的方法。

用回溯算法解决问题的一般步骤:

1、 针对所给问题,定义问题的解空间,它至少包含问题的一个(最优)解。

2 、确定易于搜索的解空间结构,使得能用回溯法方便地搜索整个解空间 。

3 、以深度优先的方式搜索解空间,并且在搜索过程中用剪枝函数避免无效搜索。

确定了解空间的组织结构后,回溯法就从开始结点(根结点)出发,以深度优先的方式搜索整个解空间。这个开始结点就成为一个活结点,同时也成为当前的扩展结点。在当前的扩展结点处,搜索向纵深方向移至一个新结点。这个新结点就成为一个新的活结点,并成为当前扩展结点。如果在当前的扩展结点处不能再向纵深方向移动,则当前扩展结点就成为死结点。此时,应往回移动(回溯)至最近的一个活结点处,并使这个活结点成为当前的扩展结点。回溯法即以这种工作方式递归地在解空间中搜索,直至找到所要求的解或解空间中已没有活结点时为止。

以下是用C++语言利用回溯法解决八皇后问题

#include<iostream>
#include<cstring>

using namespace std;
int count = 0;//用于计数
void EightQueen(int);

int main()
{
    int n;
    cout<<"Please input a number:";
    cin>>n;
    EightQueen(n);
    cout<<"All the number of placements that meet the conditions is "<<count<<"."<<endl;
    return 0;
}

//回溯法解决n皇后问题
void EightQueen(int n)
{
    int *p = new int[n];//p[i][j]表示第i个皇后位于坐标(i,j)
    memset(p,0,n*sizeof(int));//初始化为0
    int k=0;
    while(k>=0)//当回溯算法回溯到k<0时,回溯算法结束
    {
        while(p[k]<n)//只有当第k行的棋子的位置小于n,才是合法的
        {
            int i;
            for(i=0;i<k;i++)
            {
                //当两个皇后位于同一行,同一列,同一个对角线上时,不符合条件
                if(p[i]==p[k]||p[i]-p[k]==i-k||p[i]-p[k]==k-i)
                    break;
            }
            if(i<k)p[k]++;//如果i<k,则表示第k行的棋子不应该放在第p[k]列,所以p[k]应该向右再移一位
            else break;//如果i=k,则表示第k行的棋子可以放在这个位置
        }
        if(p[k]<n)//p[k]<n,表示第k行皇后的位置没有超过棋盘的大小,即对k+1层进行更深层次的搜索,或得出正确的结论
        {
            if(k<n-1)//当k<n-1时,表示还没有移动到最后一行,所以k++
                k++;
            else//当k=n-1时,表示已经移动到最后一行,开始画棋盘图形
            {
                for(int i=0;i<=k;i++)
                {
                    for(int j=0;j<p[i];j++)
                    {
                        cout<<"|-";
                    }
                    cout<<"O";
                    for(int j=0;j<k-p[i];j++)
                    {
                        cout<<"-|";
                    }
                    cout<<endl;
                }
                count++;//满足条件的次数加1
                cout<<"Type: "<<count<<endl;
                cout<<"-------------------------------------"<<endl;
                p[k]++;//将最后一行的棋子再右移一格进行下一步的搜索
            }
        }
        //当p[k]>=n时,操作不合法,进行回溯操作
        //即:将本行棋子的位置置为0,然后返回上一行,将上一行的棋子位置加1再进行深层次的搜索
        else
        {
            p[k]=0;
            k--;
            if(k>=0)p[k]++;
        }
    }
}

当输入为8时,一共92种情况

本篇博客的代码来自:https://www.bilibili.com/video/av3606406?from=search&seid=16429348211156615665

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值