洛谷 P1219 八皇后

题目描述

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

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

洛谷 P1219 八皇后

行号 1 2 3 4 5 6

列号 2 4 6 1 3 5

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

//以下的话来自usaco官方,不代表洛谷观点

特别注意: 对于更大的N(棋盘大小N x N)你的程序应当改进得更有效。不要事先计算出所有解然后只输出(或是找到一个关于它的公式),这是作弊。如果你坚持作弊,那么你登陆USACO Training的帐号删除并且不能参加USACO的任何竞赛。我警告过你了!

输入格式

一个数字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


思路

1->n行,每行存入不同的列数值即可满足各行各列有且只有一个棋子,且此时行数值和列数值就可代表各棋子的坐标,设某一棋子的行数为ind1,列数值为val1,另一棋子的行数为ind2,列数值为val2,则只要当abs(ind1 - ind2) != abs(val1 - val2)即可说明各对角线及其平行线上有且只有一个棋子。

dfs进入各行,为每一行找一个符合要求(judge函数)的列数值即可。

#include <cstdio>
#include <algorithm>

using namespace std;

const int maxn = 15;
int n, ans[maxn], cnt;   // ans保存每一行的列数,cnt为解的个数
bool used[maxn] = {false};

// 判断在第ind行存入列数值val是否可行
bool judge(int ind, int val) {
	if (used[val]) return false;   // 前面的某一行已经存过这个列数值了
	// 遍历之前已经存好了列数值的各行,判断是否满足各对角线及其平行线上只有一个棋子
	for (int pre = 1; pre < ind; ++pre) {
		// 行数值的绝对值之差不等于列数值的绝对值之差即可说明
		// 各对角线及其平行线上有且只有一个棋子
		if ( abs(pre - ind) == abs(ans[pre] - val) ) return false;
	}
	return true;
}

// 当前行数为ind
void dfs(int ind) {
	if (ind == n + 1) {
		cnt ++;
		if (cnt <= 3) {
			for (int i = 1; i <= n; ++i) {
				printf("%d", ans[i]);
				i != n ? printf(" ") : printf("\n");
			}
		}
		return;
	}
	// 遍历列数值val,若合适则存入该ind行中
	for (int val = 1; val <= n; ++val) {
		if (judge(ind, val)) {
			used[val] = true;
			//if (cnt < 3) ans[ind] = val;
			ans[ind] = val;
			dfs(ind + 1);
			used[val] = false;
		}
	}
}

int main() {
	scanf("%d", &n);
	dfs(1);
	printf("%d\n", cnt);
	return 0;
}
上一篇:手撕数据结构一:线性表


下一篇:校招 刷题