【算法分析】回溯法解八皇后问题(n皇后问题)

回溯法解题思路:
(1)针对所给问题,定义问题的解空间;   
(2)确定易于搜索的解空间结构;   
(3)以深度优先方式搜索解空间,并在搜索过程中用剪枝函数避免无效搜索。

八皇后问题:

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


图解回溯法解八皇后问题:
这里写图片描述


回溯法解N皇后问题


1、使用一个一维数组表示皇后的位置,
   其中数组的下标表示皇后所在的行,
   数组元素的值表示皇后所在的列。

2、假设前n-1行的皇后已经按照规则排列好,
   那么可以使用回溯法逐个试出第n行皇后的合法位置,
   所有皇后的初始位置都是第0列,
   那么逐个尝试就是从0试到N-1,
   如果达到N,仍未找到合法位置,
   那么就置当前行的皇后的位置为初始位置0,
   然后回退一行,且该行的皇后的位置加1,继续尝试,
   如果目前处于第0行,还要再回退,说明此问题已再无解。

3、如果当前行的皇后的位置还是在0N-1的合法范围内,
   那么首先要判断该行的皇后是否与前几行的皇后互相冲突,
   如果冲突,该行的皇后的位置加1,继续尝试,
   如果不冲突,判断下一行的皇后,
   如果已经是最后一行,说明已经找到一个解,输出这个解,
   然后最后一行的皇后的位置加1,继续尝试下一个解。

完整代码:

#include <iostream>
#include <cstdlib>

using namespace std;

bool place(int *a, int k)
{
    for(int i = 0; i < k; ++i)
    {
        if(abs(k - i) == abs(a[k] - a[i]) || a[k] == a[i])
            return false;
    }
    return true;
}

int Backtrack(int sum, int num, int *a)
{
    int i = 0;
    while(1)
    {
        if(a[i] < num)
        {
            if(!place(a,i))
            {
                a[i]++;
                continue;
            }

            if(i >= num - 1)
            {
                sum++;
                a[num - 1]++;
                continue;
            }

            i++;
            continue;
        }
        else
        {
            a[i] = 0;
            i--;

            if(i < 0)
                return sum;

            a[i]++;
            continue;
        }
    }
}

int main(int argc, char const* argv[])
{
    int sum = 0;
    int num = 0;
    cout << "input the number of queens" << endl;
    cin >> num;

    if(num < 4 && num != 1)
    {
        cout << "no sulution" << endl;
        return 0;
    }

    int *array = (int *)malloc(sizeof(int) * num);

    for(int i = 0; i < num; ++i)
    {
        array[i] = 0;
    }

    cout << Backtrack(sum, num, array) << endl;


    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值