八皇后问题 回溯法

题意:

给定一个n*n的棋盘, 皇后只能攻击他所在那一列, 左对角线, 右对角线, 求一个所有皇后的不能互相攻击的 solution。

分析:

可以从第一行开始枚举, 然后标记该列和主副对角线, 注意点(i,j)左对角线可以标记为 i+j, 右对角线是 i +(n-j), 用3个标记数组标记即可, 回溯法指的是先试试取这个点, 然后标记, 递归回来时候不要这个点, 取消标记。

/*
回溯法
每次摆放后 都把剩下的列 左右对角线标记
然后再摆放空的位置
如果到最后或者某一行找不到空的位置
就回溯
如果找到最后一行有空的摆放位置 就是答案
*/
#include<bits/stdc++.h>
using namespace std;
int vis[3][50] = {0};//vis[0]负责标记这一列 vis[1]负责标记左对角线 vis[2]负责右对角线
int n;
int ans[20];
int ok = 0;
void dfs(int row)
{
    if(row > n)//如果能走到这里 就是答案
    {
        ok++;
        if(ok <= 3)
        {
            for(int j = 1; j < row; j++)
            {
                printf("%d", ans[j] );
                if(j == row - 1) printf("
");
                else printf(" ");
            }
        }


    }
    else
    {
        for(int i = 1; i <= n; i++)
        {
            if(!vis[0][i] && !vis[1][i+row] && !vis[2][i+(n-row)]) //如果这个位置没有标记
            {
                ans[row] = i;//那vis[row+1][i-1]=vis[row+1][i+1]=vis[row][i] = 1;不能放子
                vis[0][i] = vis[1][i+row] = vis[2][i+(n-row)] = 1;//标记列 左对角线 右对角线;
                dfs(row+1);
                vis[0][i] = vis[1][i+row] = vis[2][i+(n-row)] = 0;//回溯的时候归零
            }
        }
    }
}
int main()
{
    while(scanf("%d", &n) !=EOF)
    {
    dfs(1);
    printf("%d
", ok);
    ok = 0;
    //printf("
");
    }
}
原文地址:https://www.cnblogs.com/Jadon97/p/7151594.html