设为首页 加入收藏

TOP

P1219 [USACO1.5]八皇后 Checker Challenge
2023-07-23 13:38:44 】 浏览:50
Tags:P1219 USACO1.5 Checker Challenge

好长时间没登博客园了,今天想起了账号密码,遂发一篇题解
最近因为复赛正在复健搜索,所以做了这道题
这道题说难并不是很难,但是在于这个题需要找到两个规律
以下是原题

[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

样例输入 #1

6

样例输出 #1

2 4 6 1 3 5
3 6 2 5 1 4
4 1 5 2 6 3
4

提示

【数据范围】
对于 100% 的数据,6<=n<=13

题目翻译来自NOCOW。

分析时间

我最初的1.0做法是dfs的参数枚举行,for枚举列
然后一输出,妙哉!
后来运行以后,发现输出了几万种可能。。。

怎么回事呢?

我们注意这样的一句不起眼的话

每条对角线(包括两条主对角线的所有平行线)上至多有一个棋子。

搜嘎,原来是这里没看见啊,意气风发の我翻开编译器,傻眼了:

我们应该怎样去判断到底是哪一行对角线呢?该怎么命名有规律呢?

我打开了画图,仔细的把样例画了出来

(哦,我这天才的审美)
研究了一下,发现左对角线(往左撇)和右对角线(往右撇)不能存放在一个数组里,需要用两个
于是用 lx[] 和 rx[] 来表示
聪明的人已经发现了规律

左对角线行列的和 -1 为 1~n*2-1 的编号

右对角线行 - 列 +n 为 1~n*2-1 的编号

注意:递归千万不要忘了回溯的时候恢复现场!!!

AC代码

#include<iostream>
#include<queue>

using namespace std;

int n,tot,cnt;
int a[15];
int q[15];
int lx[30];
int rx[30];
int l,r;

void dfs(int t){
	if(t>n){
		cnt++;//计数
		if(cnt<=3){
			for(int i=1;i<=n;i++) cout<<q[i]<<" ";
			cout<<endl;
		}//输出
		return ;//已经得出一个正解,返回
	}
	for(int i=1;i<=n;i++){
		if(a[i]==0){
		    if(lx[i+t-1]!=0) continue;
		    if(rx[t-i+n]!=0) continue;
			a[i]=1;
			q[++tot]=i;
			lx[i+t-1]=1;
			rx[t-i+n]=1;
			dfs(t+1);
			tot--;//回溯
			lx[i+t-1]=0;
			rx[t-i+n]=0;
			a[i]=0;
		}
	}
}

int main(){
	cin>>n;
	dfs(1);
	cout<<cnt;
} 

感谢观看!!!ありがどう!

】【打印繁体】【投稿】【收藏】 【推荐】【举报】【评论】 【关闭】 【返回顶部
上一篇继承和多重继承 下一篇C++ 一种交换两个数的思路

最新文章

热门文章

Hot 文章

Python

C 语言

C++基础

大数据基础

linux编程基础

C/C++面试题目