题目描述
检查一个如下的6 x 6的跳棋棋盘,有六个棋子被放置在棋盘上,使得每行、每列有且只有一个,每条对角线(包括两条主对角线的所有平行线)上至多有一个棋子。
上面的布局可以用序列2 4 6 1 3 5来描述,第i个数字表示在第i行的相应位置有一个棋子,如下:
行号 1 2 3 4 5 6
列号 2 4 6 1 3 5
这只是跳棋放置的一个解。请编一个程序找出所有跳棋放置的解。并把它们以上面的序列方法输出。解按字典顺序排列。请输出前3个解。最后一行是解的总个数。
输入输出格式
输入格式:
一个数字N (6 <= N <= 13) 表示棋盘是N x N大小的。
输出格式:
前三行为前三个解,每个解的两个数字之间用一个空格隔开。第四行只有一个数字,表示解的总数。
输入输出样例
输入样例#1:
6
输出样例#1:
2 4 6 1 3 5
3 6 2 5 1 4
4 1 5 2 6 3
4
我就不废话了,直接看代码及其注释即可!
#include<bits/stdc++.h> //C++万能头文件
int a[101],b[101],c[101]; //数组a用来标记列
int ans[101]; //数组b用来标记从左下到右上的对角线
int n,cnt; //数组c用来标记从左上到右下的对角线
int check(int i,int line) //check函数用来检查该位置的数是否已经被皇后占领
{
if(a[i]==1||b[line+i]==1||c[n+line-i]==1)
return 0; //我们画一张表,发现从左下到右上的对角线的
else //横纵坐标之和为定值,且为正数;而从左上到
return 1; //右下的横纵坐标之差为定值,但可能为负数,
} //我们可以加上n,确保数组在不越下界的同时,
//也不越该数组的上界
void mark(int i,int line) //mark函数用来标记该皇后占领的列和两个对角线
{
a[i]=1;
b[line+i]=1;
c[n+line-i]=1;
}
void recover(int i,int line) //解除标记,用于回溯
{
a[i]=0;
b[line+i]=0;
c[n+line-i]=0;
return;
}
void dfs(int line)
{
if(line==n+1) //给出搜索的边界条件,即终止条件
{
if(cnt++>=3) //由题意,只输出前三组答案,三组以后不输出
return;
for(int i=1;i<=n;i++)
{
if(i!=1)
printf(" ");
printf("%d",ans[i]);
}
printf("\n");
}
for(int i=1;i<=n;i++) //遍历该行(line)的每一个位置
{
if(check(i,line)) //检查该行该位置是否已被皇后占领
{
ans[line]=i; //如果没被占领,那么第line个皇后的位置
mark(i,line); //位置就是第line行第i列
dfs(line+1); //该皇后占领该位置后占领该位置的列以及
recover(i,line); //该位置的两对角线,所以调用mark函数
} //标记完后继续搜索第line+1行
} //解除标记,以便进行下一次尝试
}
int main()
{
scanf("%d",&n);
dfs(1); //从line==1开始搜索
printf("%d\n",cnt); //按题意输出满足题意的排法总数
return 0;
}