题目描述: 把 n 个皇后无伤放进n * n的棋盘上。

输出要求:按字典序输出前三个放置方案中第1~n行的皇后的列数构成的序列。

 

思路:

  核心难点在于如何记录前一个状态用于回溯。

  如果我们采用一个n * n的矩阵记录第 i 行第 j 列的格子是否被场上皇后控制,我们必须要记录有几个皇后能控制这个格子(二维int数组),否则回溯的时候会出问题,因为其他皇后可能仍然控制着这个格子。这就造成了巨大的内存开销。

  我们敏锐地注意到,其实并不需要记录每个格子是否被控制,因为每一行每一列每一条斜线都只能存在一个皇后。换言之,我们只需要记录每一行每一列每一条斜线是否被控制就可以了。第 i 行有没有被控制不需要考虑,因为我们就是基于行数进行回溯的。其他三种情况可以采用下列方法记录:

    ① 第 j 列:是很好记录的,使用一维bool数组c[ j ]。

    ② 斜率为正的斜线:y - x = k(k = -(n - 1),……,1,2,……,n - 1),一共是2n - 1条。我们敏锐地注意到,截距 k 唯一标识了一条斜线。那么,我们可以用一维bool数组x2[k + n],即x2[y - x + n]来记录。(加 n是为了让数组下标为正)

    ③斜率为负的斜线:y + x = k(k = -(n - 1),……,1,2,……,n - 1),一共是2n - 1条。同理②,我们可以用一维bool数组x1[ k ],即x1[y + x]来记录。

 

#include<iostream>
#include<cstring>
using namespace std;
int n;
int temp[105], tot, l, con;
bool c[105], x1[105], x2[105];



void Find(int st)
{
    if(st > n)
    {
        tot++;
        if(con<3)
        {
            con++;
            for(int i = 1; i <= n; i++)
            {
                if(i > 1) cout<<" ";
                cout<<temp[i];
            }
            cout<<endl;
        }
        return ;
    }
    for(int i = 1; i <= n; i++)
        if(!c[i] && !x1[st + i] && !x2[st - i + n])
        {
            c[i] = 1;
            x1[st + i] = 1;
            x2[st - i + n] = 1;
            temp[++l] = i;
            Find(st + 1);
            --l;
            c[i] = 0;
            x1[st + i] = 0;
            x2[st - i + n] = 0;
        }
}
int main()
{
    cin>>n;
    Find(1);
    cout<<tot;
    return 0;
}
回溯