现在的位置: 首页 > 综合 > 正文

八皇后问题

2018年06月07日 ⁄ 综合 ⁄ 共 2298字 ⁄ 字号 评论关闭

问题描述:八皇后问题是要求在八行八列的表格里面,要求放入8个皇后,要求所有的皇后都不能在同一行、同一列,并且不能在同一对角线上

解决方法:首先是采用回溯法(一种系统地搜索问题的解的方法),其思想是:从一条路往前走,能进则进,不能进则退回来,找另一条路继续试探

思路:

1、算法开始,清空棋盘,从棋盘的第一行第一列开始

2、检测该位置是否可以放皇后(同行、同列、对角线上都没有其他皇后),如果可以放则跳到第3步,如果冲突则跳到第4步

3、将皇后放入该位置

3.1 检测是否是最后一行,如果是则输出结果,然后将下一行设置为当前行,下一列设置为当前列,将该行的a[i]标志设置为初始值,即标志为该行皇后还没完成定位,重新新的一轮求解,

3.2 如果不是最后一行则继续下一行的皇后定位,跳到步骤2

4、列数加1

4.1如果当前列不是最后一列则跳到第2步

4.1如果当前列是最后一列,则回溯,即如果是已经是第一行了,那么结束程序。如果不是第一行则设置当前行为上一行,设置当前列为当前皇后位置的后一列,清除该行皇后的位置标志,继续步骤2。

程序说明:首先想到的是用什么数据结构表示棋盘和皇后,最直接的想法可能是用一个二维的数组表示,但是其实有一种很巧妙的做法,就是用一个一维的数组就搞定了,例如a[i]=j;表示有皇后在第i行的第j列,该数组的皇后已经不可能在同一行了,

判断位置是否可以,可以从是否同一列(用a[i]=col)和是否对角线上(可以利用线段斜率为-1判断,即abs(row-i)=abs(a[i]-col)

非递归方法:

#include<stdio.h>
#include<math.h>
#define QUEEN 8
#define INITIAL -1000
int a[QUEEN];
void init()
{
	int p;
	for(p=0;p<QUEEN;p++)
	{
		a[p] = INITIAL;
	}
}
int value(int row,int col)
{
		int i;
	for (i = 0; i < QUEEN; ++i)   //对棋盘进行扫描
	{
		if (a[i] == col || abs(i - row) == abs(a[i] - col))   //判断列冲突与斜线上的冲突
			return 0;
	}
	return 1;
}
void print(){
	int i, j;
	for (i = 0; i < QUEEN; ++i)
	{
		for (j = 0; j < QUEEN; ++j)
		{
			if (a[i] != j)      //a[i]为初始值
				printf("%c ", '.');
			else                //a[i]表示在第i行的第a[i]列可以放置皇后
				printf("%c ", '#');
		}
		printf("\n");
	}
	for (i = 0; i < QUEEN; ++i)
		printf("%d ", a[i]);
	printf("\n");
	printf("--------------------------------\n");

}
void queen(){
	int i,j,n=0;
	i=0;
	j=0;
	while(i<QUEEN)//i行
	{
		while(j<QUEEN)//j列
		{
			if(value(i,j))//判断该位置是否可以放皇后
			{
			    a[i]=j;//放置皇后
			    j=0;
			    break;
			}
			else
			{
			    j++;
			}
		}
		if(a[i]==INITIAL)//该行是否已经找到放皇后的位置
		{
		    if(i==0)//已经回溯回到第一行了,程序结束
		    {
			break;
		    }
		    else
		    {
			--i;//设置当前行为该行
			j=a[i]+1;//设置当前列为当前行皇后位置的下一列
		        a[i] = INITIAL;//清除该行的标志
			continue;
		    }
		}
		if(i==QUEEN-1)//得到一种情况
		{
		    printf("第%d种方式\n",++n);
		    print();//打印该情况
		    j=a[i]+1;//设置当前列为皇后位置的下一列
		    a[i]=INITIAL;//清除该行的标志
		    continue;
		}
		i++;//下一行
	}
}
int main(void)
{
	init();
	queen();
	return ;
}

递归方法:

#include <stdio.h>
#include <stdlib.h>

const int N=20;   //最多放皇后的个数
int q[N];         //各皇后所在的行号
int cont = 0;     //统计解得个数
//输出一个解
void print(int n)
{
	int i,j;
	cont++;
	printf("第%d个解:",cont);
	for(i=1;i<=n;i++)
		printf("(%d,%d) ",i,q[i]);
	printf("\n");
	for(i=1;i<=n;i++)        //行
	{                
		for(j=1;j<=n;j++)    //列
		{
			if(q[i]!=j)
				printf("x ");
			else 
				printf("Q "); 
		}
		printf("\n");
	}
}
//检验第i行的k列上是否可以摆放皇后
int find(int i,int k)  
{
	int j=1;
	while(j<i)  //j=1~i-1是已经放置了皇后的行
	{
		//第j行的皇后是否在k列或(j,q[j])与(i,k)是否在斜线上
		if(q[j]==k || abs(j-i)==abs(q[j]-k)) 
			return 0;
		j++;
	}
	return 1;
}
//放置皇后到棋盘上
void place(int k,int n)  
{
	int j;
	if(k>n)
		print(n);
	else
	{
		for(j=1;j<=n;j++)   //试探第k行的每一个列
		{
			if(find(k,j))
			{
				q[k] = j;
				place(k+1,n);  //递归总是在成功完成了上次的任务的时候才做下一个任务
			}
		}
	}
}
int main(void)
{
	place(1,8);        //问题从最初状态解起
	system("pause");
	return 0;
}



抱歉!评论已关闭.