习题:八皇后问题

题目
八皇后问题,在 8×8 的国际象棋棋盘上摆放8个皇后,使其不能互相攻击,即任意两个皇后都不能处于同一行、同一列或同一斜线上,问有多少种摆法,并打印每一种摆法。


解题思路
在这里插入图片描述
判断方法:
从上向下依次每行摆放一个皇后,这样就不需要判断一行中是否会不止一个皇后。
在摆放时判断一个位置是否可以摆放皇后:
1.黄色线上只能有一个皇后;对于黄色线上的任意两个方格坐标 (i, j) 、(row, col) 满足 row - i = col -j 。
2.蓝色线上只能有一个皇后;对于蓝色线上则是 row + col = i + j 。
3.同一列只能有一个。

摆放过程:
在添加过程中,每一行都从左向右摆放,当冲突时就摆下一列,如果不冲突就在这个位置摆上皇后,然后去摆下一行;如果这一列摆完也没有找到不冲突的位置,就回退到上一行,将皇后向右移一列。
不断循环上述过程,当最后一行也摆放上皇后之后,这时候就找到一种摆法了。


代码实现:
使用二维数组

#include <stdio.h>

//判断位置row、col是否可以放下皇后
int judge(int queens[][8], int row, int col)
{
	for(int i=0; i<row; i++)
	{//在摆放row,col位置时,0~row-1行已经摆放过
		for(int j=0; j<8; j++)
		{// 二维数组元素为1表示已经摆放了皇后
			if(row-i == col-j && 1 == queens[i][j])
			{//黄色斜线
				return 0;
			}
			if(row+col == i+j && 1 == queens[i][j])
			{//蓝色斜线
				return 0;
			}
		}
		if(1 == queens[i][col])
		{//同一列只能摆放一个
			return 0;
		}
	}
	return 1;
}

int judge1(int queens[][8], int row, int col)
{
	for(int i=1; row-i >= 0 && col-i >= 0; i++)
	{//黄色斜线
		if(1 == queens[row-i][col-i])
		{
			return 0;
		}
	}
	for(int i=1; row-i>=0 && col+i<8;i++)
	{//蓝色斜线
		if(1 == queens[row-i][col+i])
		{
			return 0;
		}
	}
	for(int i=0; i<row; i++)
	{//同一列
		if(1 == queens[i][col])
		{
			return 0;
		}
	}
	return 1;
}

//打印摆放方法
void showqueens(int queens[][8], int n)
{
	printf("------------------------\n");
	for(int i=0; i<8; i++)
	{
		for(int j=0; j<8; j++)
		{
			printf("%d ", queens[i][j]);
		}
		printf("\n");
	}
	printf("------------------------\n");
}

//打印所有摆放方法,并返回方法个数
int putqueens(int queens[][8], int n)
{
	int i=0, j=0;//当前需要摆放的位置
	int cnt=0;//方法个数
	while(1)
	{
		if(judge(queens, i, j))
		{//(i, j)可以摆放
			queens[i][j] = 1;//1表示已经摆放了
			i++;//摆放下一行
			j=0;//摆放下一行时从第一列开始摆放
		}
		else
		{//(i, j)不可以摆放
			j++;//摆放下一列
		}
		while(8 == j)
		{//当i行没有一个位置能够摆放时
			i--;//去i-1行
			for(int m=0; m<8; m++)
			{
				if(1 == queens[i][m])
				{
					queens[i][m] = 0;//0表示没有摆放皇后
					j = m+1;//将i-1行的皇后像后移一位
				}
			}
		}
		if(8 == i)
		{//如果已经摆放了8个皇后
			showqueens(queens, 8);//打印摆法
			cnt++;//摆法方法+1
			do{
				i--;//去i-1行找下一种的摆法
				for(int m=0; m<8; m++)
				{
					if(1 == queens[i][m])
					{
						queens[i][m] = 0;
						j = m+1;
					}
				}
			}while(8 == j);
		}
		if(-1 == i)
		{//所有方法都找到时
			return cnt;
		}
	}
}

int main()
{
	int q[8][8]={};
	int m = putqueens(q, 8);
	printf("%d\n", m);
	return 0;
}

一维数组
这里用一个长度为 8 的一维数组实现,数组元素值的范围是0~7,对应二维数组的列,queens[row] = col 表示(row, col) 这个位置有一个皇后。

#include <stdio.h>

int judge(int queens[], int row, int col)
{
	for(int i=0; i<row; i++)
	{
		if(col == queens[i] || row-i == col-queens[i] || row+col == i+queens[i])
		{
			return 0;
		}
	}
	return 1;
}

int show(int queens[], int n)
{
	for(int i=0; i<n; i++)
	{
		printf("%d ", queens[i]);
	}
	printf("\n");
}

int putqueens(int queens[], int n)
{
	int i=0, j=0;
	int cnt=0;
	while(1)
	{
		if(judge(queens, i, j))
		{
			queens[i] = j;
			i++;
			j=0;
			if(i == n)
			{
				show(queens,8);
				cnt++;
				do{
					i--;
					j = queens[i] + 1;//j可能超过最大值
				}while(j == n);
			}
		}
		else
		{
			j++;
			while(j == n)
			{
				i--;
				j = queens[i] + 1;
			}
		}
		if(-1 == i)
		{
			return cnt;
		}
	}
}

int main()
{
	int q[8] = {};
	int n = putqueens(q, 8);
	printf("%d\n", n);
	return 0;
}

结果总共有92种。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值