洛谷——p1219 八皇后

用简短代码做出这个题,有这样一个题目:它的标签是深度搜索dfs,但是我做这个题目的时候却不知道从哪里下手,但是理解题目意思之后,这个代码解决就很轻松了。

题目是这样的:

【题目描述】

一个如下的 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 大小的。

【输出】

前三行为前三个解,每个解的两个数字之间用一个空格隔开。第四行只有一个数字,表示解的总数。

【提示】

数据范围:
对于 100% 的数据,6≤n≤13。

样例输入

6

样例输出

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

6×6 的跳跳棋盘满足题意的四种情况:

 

 

 

 

解题思路

我首先想的是:把整个棋盘都遍历一遍,如果一个棋子被放置在一个点,那就把这个点的行,列及其两个斜线都用book二维数组标记为 1,之后要放置棋子要满足 book 数组的值为 0,然后放置后继续标记。

但是这个方法不太好实现,因为每选择一个棋子,就要把它的行,列及其斜线上面的book数组标记,并且实现了 n 列后,要取消标记。

 由上述图可知:每一个皇后(棋子)都单独占一行,单独占一列,单独占从左上至右下的对角线,单独占从右上至左上的对角线。

那可以换一个角度,不是非要一个二维数组来标记,三个方向(列,两个斜线方向)都可以用一个数组标记(b[100],c[100],d[100] 初始化为 0 ),并且每一个数组被标记了,那个所标记的点就不能放置棋子了(如b[1]=1,代表第一列被标记了,不能放棋子了)。那行 i 用不用标记呢?行是需要标记的,但是我们用行来循环,记录棋子的位置,记录行坐标的是 a[100],a[1]的值代表第一行棋子的位置。

现在又出现了一个问题,两个斜线方向要怎么用一维数组记录,然后标记呢?

可以找找规律......

每一条由右上至左下的斜线,行 i 加上列 j 是相等的;每一条由左上至右下的斜线,行 i 减去列 j 是相等的,但是这里要注意一个问题:有些数据的行 i 减去列 j 是负数,而对于这个数字,数组会越界而不能被标记。

然后我第一个想法是:用行减去列的绝对值 abs( i - j )来记录左上至右下的斜线,但是这样计算出来的会有不同的斜线重复,数组不能准确代表某一个斜线,所以用行减去列再加上棋盘的范围 i - j + n 来记录,这个( i - j + n)也始终是正数。

这些问题都解决了,就可以用代码解决了:

代码如下:

#include<stdio.h>
int a[100],b[100],c[100],d[100];
int n,s;
void fun(int k)//k为行数 
{
	int i,j;
	for(i=1;i<=n;i++)//遍历列 
	{
		if(b[i]==0&&c[i+k]==0&&d[i-k+n]==0)
		{
			//如果满足未被三个数组标记的条件,就用数组 a 记录下这个第 k 行的列数 
			//并且把这个放置棋子的点标记 
			a[k]=i;
			b[i]=1;
			c[i+k]=1;
			d[i-k+n]=1;
			if(k==n)
			{
				//题目要求输出前三个方案,每一行代表的数组 
				s++;
				//那就用一个 if 语句判断 
				if(s<=3)
				{
					for(j=1;j<=n;j++)
			    	printf("%d ",a[j]);
			    	printf("\n");
				}
			}
			//如果每行没有遍历到,则继续向下进入函数 
			else
			fun(k+1);
			//出函数要把标记解除,否则会影响下一个循环 
			b[i]=0;
			c[i+k]=0;
			d[i-k+n]=0;
		}
	}
}
int main()
{
	scanf("%d",&n);
	fun(1);//从行数为 1 开始遍历 
	printf("%d",s);//输出方案的个数 
	return 0;
}

这个题目大概就是这样,注意标记可以用多个数组共同实现。

 

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
洛谷八皇后问题是一个经典的回溯算法问题。根据引用中的描述,要求将8个皇后放置在8*8棋盘上,使得它们彼此不受攻击,即任何两个皇后都不在同一行、同一列或同一斜线上。 引用[2]给出了一个c++代码的实现。这段代码使用了回溯法来解决八皇后问题。通过递归地尝试每一行中的每一列,找到合适的位置来放置皇后。 具体的过程如下: 1. 定义一个一维数组x,用来存储每行皇后的位置。 2. 从第一行开始递归,尝试每一列的位置。 3. 对于每个位置,检查是否与之前的皇后位置冲突,即是否在同一列或同一对角线上。如果冲突,就继续尝试下一列;如果不冲突,就将该位置存入数组x,并继续递归下一行。 4. 当递归到最后一行时,打印出当前的皇后位置,并将可行解的数量加一。 5. 回溯到上一行,尝试下一个列的位置。 6. 当所有的解都找到后,输出解的数量。 根据引用给出的代码,共有92种不同的放置方式,即解的数量为92。<span class="em">1</span><span class="em">2</span> #### 引用[.reference_title] - *1* [8皇后_八皇后问题c++实现_](https://download.csdn.net/download/weixin_42665725/26278676)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_1"}}] [.reference_item style="max-width: 50%"] - *2* [八皇后问题C++递归回溯法(注解)](https://blog.csdn.net/qq_43656233/article/details/105571396)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_1"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

明里灰

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值