问题描述:
这是一个经典的关于组合学的问题:在一个国际象棋中的的棋盘上放置8个皇后, 为了使其中的任何2个皇后都不能相互“攻击”,希望寻求8个皇后的安全放置位置。 该问题的不能相互“攻击”相当于要求任意两个皇后不能在同一行、同一列或同一斜线上。求解可能的方案及方案数。
思路:一般采用回溯法。
易知,每行肯定有一个皇后,但是放在哪一列需要查找。这样,可以采用回溯法试探。
当某一列找不到合适的位置,那么上一个皇后得重新寻找合适的位置,如果还找不到(即,当前给皇后放到最后一列了,还是与之前所有放置好的皇后要不同行要不同列要不同斜线方向),那么就继续回溯到上上一个皇后等等。当回溯到第一个皇后时,这个皇后如果放到最后一列还是让其他的皇后没有位置可以放,那么就说明放不了,失败,退出。
如果八个皇后都放好且不冲突,那么成功,退出。
从(0,0)开始,放第一个皇后,剩下的七个皇后怎么放?
如下代码计算出第一种解法:
#include "stdio.h"
#include "stdlib.h"
#define LINES 8 // 定义行数
#define COLS 8 // 定义列数
void visit(int Q[LINES])
{
int i=0;
printf("the result of eight queen: \n");
while(i<LINES)
{
printf("(%d, %d)",i,Q[i]);
i++;
}
}
int canplace(int Q[],int k)
{
int i;
for(i=0; i<k; i++)
{
//if( (Q[k]==Q[i]) || ((Q[k]-k)==(Q[i]-i)) || ((Q[k]+k)==(Q[i]+i)) )//两个位置任意一行、一列、正斜向、反斜向只要有一个条件满足,此位置不可放皇后
if( (Q[k]==Q[i]) || (abs(Q[k]-Q[i])==abs(k-i)) )//换一种判断,判断正斜向反斜向只要想到数学的直线斜率为正负一就可以简化
return 0;//表示第k个皇后不能放
}
return 1;
}
int EightQueen(int Q[LINES])
{
int k = 1,i,find,temp;
Q[0] = 0;
while(k>0)
{
find = 0;//find标志,表示
for(i=0; i < COLS; i++)
{
//Q[k] = i 会出现死循环调不出来。回溯时下一个皇后找不到合适的列,又给上一个皇后找到上一个第一个合适的列。
Q[k]++ ;
if((Q[k]<COLS)&&canplace(Q,k))
{
find = 1;
break;
}
}
if(find == 1)//第k+1个皇后找到合适的列
{
if(k==7)//八个皇后都安置正确
{
visit(Q);
return 1;
}
else//查找下一个皇后的位置
{
k++;
}
}
else // 第K+1个皇后找不到合适的列,即它放置的位置与前k个皇后冲突,那么应该重新放置第k个皇后;
{
Q[k] = -1; //重新把当前的皇后位置设为-1,表示没有寻找。
k--;
}
}
if(k == 0)
{
printf("Sorry!");
return 0;
}
}
void main()
{
int Q[LINES],i;
for(i=0; i<LINES; i++)
Q[i]=-1;//把所有的皇后位置设为-1,表示没有寻找
EightQueen(Q);
}
但是,查百度,知道八皇后问题有92种解法。故修改了下EightQueen(Q),具体代码如下:
int EightQueen(int Q[LINES])
{
int k = 1,i,find,temp,count = 0;
Q[0] = 0;
while(k>=0)//为了使求解下一轮解法时,仍在此循环中,故k可以取0
{
find = 0;
for(i=0; i < COLS; i++)
{
//Q[k] = i 会出现死循环调不出来。回溯时下一个皇后找不到合适的列,又给上一个皇后找到上一个第一个合适的列。
Q[k]++ ;
if((Q[k]<COLS)&&canplace(Q,k))
{
find = 1;
break;
}
}
if(find == 1)//第k+1个皇后找到合适的列
{
if(k==7)//八个皇后都安置正确
{
visit(Q);
//return 1;
count++;
printf("下一轮解法\n");
}
else//查找下一个皇后的位置
{
k++;
}
}
else // 第K+1个皇后找不到合适的列,即它放置的位置与前k个皇后冲突,那么应该重新放置第k个皇后;
{
Q[k] = -1;
k--;
}
}
printf("\n最终的解法数count=%d",count);
}
这个程序相较于之前那个找到八个皇后位置就返回程序结束不同,此时,仍会执行到while(k >=0),这时”(find == 1)//第k+1个皇后找到合适的"不满足,这样会执行else,即又重新把Q[k]赋值为-1,直到从某个皇后开始,换一列仍有合适的解法,程序又开始执行查询下一个皇后。
文章知识点与官方知识档案匹配,可进一步学习相关知识
C技能树首页概览134665 人正在系统学习中