P1219——[USACO1.5]八皇后 Checker Challenge——递归/回溯算法
P1219——[USACO1.5]八皇后 Checker Challenge——递归/回溯算法
题目描述
一个如下的6×6 的跳棋棋盘,有六个棋子被放置在棋盘上,使得每行、每列有且只有一个,每条对角线(包括两条主对角线的所有平行线)上至多有一个棋子。
上面的布局可以用序列 2 4 6 1 3 5 来描述,第 i个数字表示在第 i行的相应位置有一个棋子,如下:
行号 1 2 3 4 5 6
列号 2 4 6 1 3 5
这只是棋子放置的一个解。请编一个程序找出所有棋子放置的解。
并把它们以上面的序列方法输出,解按字典顺序排列。
请输出前 3个解。最后一行是解的总个数。
输入格式
一行一个正整数 n,表示棋盘是n×n大小的。
输出格式
前三行为前三个解,每个解的两个数字之间用一个空格隔开。第四行只有一个数字,表示解的总数。
输入输出样例
输入 1
6
输出 1
2 4 6 1 3 5
3 6 2 5 1 4
4 1 5 2 6 3
4
说明/提示
【数据范围】
对于 100%100% 的数据,6≤ n ≤13。
题解/思路:
惯例,先吐槽一下我自个的憨:题目描述中的图,行列是从1开始,如 6x6 ,然后我这个憨憨,写的时候考虑到使用数组,我就从0开始写的,然后试样例的时候,我发现我的运行结果和样例差很远,人都傻了。(也没卡多久,也就半把个小时吧,害)
解题思路:
题目大意如下:放置棋子的位置所在的行,列,与主对角线/副对角线平行的线所在的位置均不能有棋子与之冲突
解题思路基本上写在代码中了,这里再解释一个东西,即对主对角线/副对角线和其平行线出位置的判断:
主对角线:行号减列号,由于用数组存数,所以再加上 n-1,如下图就加上5(6-1),
副对角线类似,为了与主对角线区别,所以,以 行号加列号 进行记录
噢,还有由于题目要求,只用输出前三组,所以在输出的时候记得做一个小判断噢,顺便贴一下,小破站讲八皇后问题讲的很好的(我觉得)一个视频:https://www.bilibili.com/video/BV1wJ411U7Gy?p=1&share_medium=android&share_plat=android&share_source=QQ&share_tag=s_i×tamp=1609919821&unique_k=ZscPxK
代码如下:
#include <bits/stdc++.h>
using namespace std;
int place[13]={0};//第n个皇后所占位置的列号
bool flag[13]={1,1,1,1,1,1,1,1,1,1,1,1,1};//标志数组,表示第col列是否可占,1表示可占领
bool d1[25]={1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1};//主对角线是否被占领的标记,行列相减再加n-1
bool d2[25]={1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1};//副对角线是否被占领的标记,行列相加
int number=0;//统计解的数量
void King(int a,int n);
int main()
{
int n;
cin>>n;
King(0,n);
cout<<number<<endl;
return 0;
}
void King(int a,int n)
{
int col;
for(col=0;col<n;col++)
{
if(flag[col] && d1[a-col+(n-1)] && d2[a+col])
{
place[a]=col;//在a行col列放置皇后
//宣布占领
flag[col] = false;
d1[a-col+(n-1)] = false;
d2[a+col] = false;
if(a<(n-1))//第col行,放置之后,继续考虑这一行的下一行
King(a+1,n);//递归
else//n个皇后都被放完了,打印结果
{
number++;
if(number<=3)
{
for(int i=0;i<n;i++)
{
cout<<place[i]+1<<' ';//俺从0行0列开始的,所以需要在输出的时候+1
}
cout<<endl;
}
}
//棋盘复原,考虑其他情况,回溯(这个真的好难,呜呜)
flag[col] = true;//(1为ture,0为false)
d1[a-col+(n-1)] = true;
d2[a+col] = true;
}
}
}