算法之n皇后问题

1. 问题描述:n×n的棋盘上放置彼此不受攻击的n个皇后。按照国际象棋的规则,皇后可以攻击与之处在同一行或同一列或同一斜线上的棋子。n皇后问题等价于在n×n的棋盘上放置n个皇后,任何2个皇后不能放在同一行或同一列或同一斜线上。

2. 问题分析:

n元数组x[n]表示问题的解。其中x[i]表示皇后i放在棋盘第i行第x[i]列。由于不允许将2个皇后放在同一列上,所以解向量中的x[i]互不相同,

2个皇后不能放在同一斜线上是问题的隐约束。设2个皇后的放置位置分别是(i,j)(k,l),则如果满足|i-k|=|j-l|,就表明2个皇后位于同一条斜线上。

分析可知,解空间树是完全n叉树,剪枝函数剪去不满足行、列、斜线约束的子树。

#include <iostream>
#include <cmath>
using namespace std;

int N=5;
int x[5]; //可行解
int sum=0;//可行解数量

bool Place(int k)
{
    for(int i=0; i<k; i++)
    {
        if(abs(k-i)==abs(x[i]-x[k])||x[i]==x[k])return false;
    }
    return true;
}
void Backtrack(int t)    //递归回溯
{
    if(t>=N)
    {
        sum++;//到达叶子结点,即找到了一个新的可行解,则解的数量sum++;
        for(int i=0; i<N; i++)
        {
            cout<<x[i]<<" ";
        }
        cout<<endl;
    }
    else
    {
        for(int i=0; i<N; i++)
        {
            x[t]=i;
            if(Place(t))Backtrack(t+1);
        }
    }
}

void Backtrack2()    //迭代回溯
{
    x[0]=0;
    int k=0;
    while(k>=0)
    {
        while(x[k]<N&&Place(k)==false)x[k]+=1;
        if(x[k]<N)
        {
            if(k==N-1)      //到了叶子结点,输出一个解,回溯
            {
                sum++;
                for(int i=0; i<N; i++)
                {
                    cout<<x[i]<<" ";
                }
                cout<<endl;
                k--;
                x[k]+=1;
            }
            else    //没到叶子结点继续往下走
            {
                k++;
                x[k]=0;
            }
        }
        else    //说明当前行无法放置,回溯
        {
            k--;
            x[k]+=1;
        }
    }
}
int main()
{
    //Backtrack(0);
    Backtrack2();

    /*0 2 4 1 3
    0 3 1 4 2
    1 3 0 2 4
    1 4 2 0 3
    2 0 3 1 4
    2 4 1 3 0
    3 0 2 4 1
    3 1 4 2 0
    4 1 3 0 2
    4 2 0 3 1*/
}

3.时间复杂度:最坏时间复杂度Place方法O(n),所以Backtrack方法时间复杂度为O(n^3);




猜你喜欢

转载自blog.csdn.net/qq_35503380/article/details/80446241