问题描述:八皇后问题是要求在八行八列的表格里面,要求放入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;
}