深圳幻海软件技术有限公司 欢迎您!

c解决八皇后问题

2023-03-25

问题描述:这是一个经典的关于组合学的问题:在一个国际象棋中的的棋盘上放置8个皇后,为了使其中的任何2个皇后都不能相互“攻击”,希望寻求8个皇后的安全放置位置。该问题的不能相互“攻击”相当于要求任意两个皇后不能在同一行、同一列或同一斜线上。求解可能的方案及方案数。思路:一般采用回溯法。易知,每行肯定有

问题描述:

这是一个经典的关于组合学的问题:在一个国际象棋中的的棋盘上放置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 人正在系统学习中