详细的八皇后摆放问题

原题在洛谷P1219;
题目描述
一个如下的 6 \times 66×6 的跳棋棋盘,有六个棋子被放置在棋盘上,使得每行、每列有且只有一个,每条对角线(包括两条主对角线的所有平行线)上至多有一个棋子

在这里插入图片描述
上面的布局可以用序列 2 4 6 1 3 5 来描述,第 ii 个数字表示在第 ii 行的相应位置有一个棋子,如下:

行号 1 2 3 4 5 6

列号 2 4 6 1 3 5

这只是棋子放置的一个解。请编一个程序找出所有棋子放置的解。
并把它们以上面的序列方法输出,解按字典顺序排列。
请输出前 3 个解。最后一行是解的总个数。

输入格式
一行一个正整数 n,表示棋盘是 m×n 大小的。

输出格式
前三行为前三个解,每个解的两个数字之间用一个空格隔开。第四行只有一个数字,表示解的总数。
输入输出样例
输入
6
输出
2 4 6 1 3 5
3 6 2 5 1 4
4 1 5 2 6 3
4
下面大概我理解的题意:
在这里插入图片描述

//O 为皇后 X不能放的位置
假设第一行(i)第四列(k)放皇后那么横竖不能再放皇后,从左上到右下的对角线和右上到左下的对角线也不能放
核心代码:
if (!lie [k] && !left1[k+x] && !right1[x-k+n])
行我们就便利一次可以减少复杂度,lie是列
看图可以发现 i+k 就可以求到左上到右下的对角线
同理的x-k是一样的,为什么加n,因为x-k可能越界;
我用dfs(x)当行

下面请看代码
#include
using namespace std;

#define a 40
int rooms [a];
bool lie[a];
bool left1[a];
bool right1[a];
int n,cnt =0;
void av()
{
if (cnt <=3)
{
for (int i=1; i<=n; i++)
cout << rooms [i]<<’ ';
cout <<endl;
}
}
void dfs (int x)
{
if (x>n)
{
cnt ++;
av();
return ;
}
for (int k=1; k<=n; k++)
if (!lie [k] && !left1[k+x] && !right1[x-k+n])
{
lie [k]=1;
left1[k+x]=1;
right1[x-k+n]=1;
rooms [x]=k;
dfs (x+1);
lie [k]=0;
left1[k+x]=0;
right1[x-k+n]=0;
}
}
int main ()
{
cin >> n;
dfs (1);
cout << cnt ;
return 0;
}
这里是回溯:
lie [k]=1;
left1[k+x]=1;
right1[x-k+n]=1;
rooms [x]=k;
dfs (x+1);
lie [k]=0;
left1[k+x]=0;
right1[x-k+n]=0;
这一步无法再放回溯到上一步重新摆放;
概念大致是此路不通回到上一个节点看看是否还有别的路可以走,如果没有就再上一个节点,这就是为什么 lie [k]=1,后面要lie [k]=0;

  • 3
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值