P1219 [USACO1.5]八皇后 Checker Challenge

一个如下的 6×6 的跳棋棋盘,有六个棋子被放置在棋盘上,使得每行、每列有且只有一个,每条对角线(包括两条主对角线的所有平行线)上至多有一个棋子。

上面的布局可以用序列 2 4 6 1 3 5 来描述,第 个数字表示在第 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% 的数据,6n13。

题目翻译来自NOCOW。

USACO Training Section 1.5

 

瞎鸡儿写(分析)

显然这道题可以用dfs,而且如果按行搜索的话,就会默认按字典序输出答案,省去了排序的过程。

用三个数组分别标记棋子所在的行,列,对角线是否还能再填入棋子。

对于对角线的处理:按行填入棋子的话,棋子上方的对角线就不需要进行处理了,因为上方已经被表示行的数组标记过了。

 

代码

```cpp

#include<bits/stdc++.h>
using namespace std;
#define N 100
int r[N][N]//标记行,c[N][N]//标记列,k[N][N]//标记对角线,ans[N]//记录答案,tot//纪录合法摆法的个数,n;
void gao(int x,int y,int z)//标记对角线已经被占用,由于不同棋子的对角线可能会有重合,所以标记用k[][]++,回溯时用k[][]--,
{
if(z==1)
{
for (int i = x, j = y; i <= n || j <= n; i++, j++)
k[i][j] += 1;
for(int i = x, j = y; i <= n || j >= 1; i++, j--)
k[i][j] += 1;
}
else
{
for (int i = x, j = y; i <= n || j <= n; i++, j++)
k[i][j] -= 1;
for(int i = x, j = y; i <= n || j >= 1; i++, j--)
k[i][j] -= 1;
}
}
void dfs(int x)
{
if(x>n)//棋子按行放置完成,输出答案
{
tot++;
if(tot<=3)
{
for(int i=1;i<=n;i++)
cout << ans[i] <<' ';
cout << endl ;
}
return;
}
for(int i=1;i<=n;i++)//开始判断
{
if(r[1][i]==0&&c[1][i]==0&&k[x][i]==0)
{
ans[x]=i;
r[1][i]=1,c[1][i]=1;
gao(x,i,1);
dfs(x+1);
r[1][i]=0,c[1][i]=0;
gao(x,i,0);
}
}
}
int main()
{
cin >> n ;
dfs(1);
cout << tot ;
return 0;
}
```
posted @ 2020-12-13 13:41  屑魔女伊蕾娜  阅读(121)  评论(0)    收藏  举报