回溯法解决 求有多少种放置皇后的放法 问题

问题描述

  给定一个n*n的棋盘,棋盘中有一些位置不能放皇后。现在要向棋盘中放入n个黑皇后和n个白皇后,使任意的两个黑皇后都不在同一行、同一列或同一条对角线上,任意的两个白皇后都不在同一行、同一列或同一条对角线上。问总共有多少种放法?n小于等于8。

输入格式
  输入的第一行为一个整数n,表示棋盘的大小。
  接下来n行,每行n个0或1的整数,如果一个整数为1,表示对应的位置可以放皇后,如果一个整数为0,表示对应的位置不可以放皇后。
输出格式
  输出一个整数,表示总共有多少种放法。
样例输入
4
1 1 1 1
1 1 1 1
1 1 1 1
1 1 1 1
样例输出
2
样例输入
4
1 0 1 1
1 1 1 1
1 1 1 1
1 1 1 1
样例输出
0

问题分析:这是典型的八皇后问题,可以使用回溯法解决。回溯算法实际上是一个类似枚举的搜索尝试方法,它的主题思想是在搜索尝试过程中寻找问题的解,当发现已不满足求解条件时,就“回溯”返回,尝试别的路径当然在尝试成功时,则问题的解算法结束。

        上述是回溯算法的基本思想,现在扯回来看这道题。首先分析一下题意,意思是不管是黑皇后还是白皇后都不能将同样颜色的皇后放在同一行和同列以及对角线上。怎么开始做呢,可以解决存储棋盘的问题,最方便直接的就是用二维数组存储,很简单。然后输入1和0在相应的位置上(可以把二维数组想象成二维的,但不能认为在内存中就是二维存储的)。判断第x行是否存在皇后,由于行之间不能存在相同,这个可以省略,直接将行带入递归中,然后是判断第i列是否可以放置皇后,再判断一下正负对角线是否有相同皇后。

#include<stdio.h>
#define _CRT_SECURE_NO_WARNINGS

int sum = 0;

int main()
{
	int Hui_su(int n, int x, int queen[][8], int s);
	int test(int n, int x, int y, int queen[][8], int s);
	int queen[8][8];
	int i, j;
	int n;   //输入数字n,形成n行n列的棋盘

	printf("请输入数字n(n<=8):");
	scanf("%d", &n);

	printf("请输入棋盘格式:\n");

	for (i = 0; i < n; i++)
	{
		for (j = 0; j < n; j++)
		{
			scanf("%d", &queen[i][j]);
		}
	}

	Hui_su(n, 0, queen, 2);//从0开始

	printf("%d\n", sum);
	return 0;


}

int Hui_su(int n, int x, int queen[][8], int s)//n是创建棋盘的大小,x为横轴坐标,queen为数组用于检验,s用于标记黑皇后和白皇后(黑2白3)
{
	int i;
	if (x == n)			//当把黑皇后检验完成后开始检验白皇后		
	{
		if (s == 2)	Hui_su(n, 0, queen, 3);
		else
			sum++;
		return 0;

	}
	for (i = 0; i < n; i++)
	{
		if (queen[x][i] != 1) continue;
		if (test(n, x, i, queen, s)) queen[x][i] = s;   //如果i列,和对角线位置检验都没有相同皇后出现,就将其设为2
		else continue;

		Hui_su(n, x + 1, queen, s);                //继续追溯

		queen[x][i] = 1;				//将其对应位置恢复为1,用于白皇后的继续检验
	}

	return 0;

}
int test(int n, int x, int y, int queen[][8], int s)//判断第y列,对角线是否有相同皇后,有的话返回0,没有返回1
{
	int i, j;
	for (i = x - 1; i>=0; i--)//判断第i列是否有相同皇后
	{
		if (queen[i][y] == s) 
			return 0;
	}
	for (i = x - 1,j = y - 1; i >= 0 && j >= 0; i--, j--)//判断正对角线是否存在相同皇后
	{
		if (queen[i][j] == s) 
			return 0;
	}
		for (i = x - 1, j = y + 1; i >= 0 && j < n; i--, j++)判断负对角线是否存在相同皇后
		{
			if (queen[i][j] == s) 
				return 0;
		}
	return 1;

        

阅读更多
换一批

没有更多推荐了,返回首页