回溯法之八皇后的C语言实现(一解)

#include <stdio.h>

#include <stdlib.h>

void* queens(int c[8],int chess[8][8]);       //八皇后回溯算法

int reasonalbe(int chess[8][8]);              //用于判断棋子是否合法

void printchess(int chess[8][8],int c[8]);    //输出棋盘阵列

void putchess(int chess[8][8],int c[8]);      //放置皇后

void print_c(int c[8]);                       //输出一维数组,显示每行皇后的位置

int main()
{
    int i,j;                                  //i为行,j为列

    int c[8]={0,0,0,0,0,0,0,0};               //存储每行皇后的位置

    int chess[8][8];                          //棋盘数据结构


    for(i = 0;i < 8;i++)                      //棋盘数据初始化
        for(j = 0;j < 8;j++)
            chess[i][j] = 0;


    printchess(chess,c);                      //显示初始化之后的结果
    queens(c,chess);                          //执行八皇后算法
    return 0;
}

void* queens(int c[8],int chess[8][8])
{
    int k = 0;
    int flag = 0;

    while(k >= 0 && flag == 0)
    {
        while(c[k] <= 8 && flag == 0)
        {
            printf("每行的皇后位置如下表:");

            c[k] = c[k] + 1;

            print_c(c);                        //输出每行皇后的位置

            putchess(chess,c);                 //放置皇后

            printchess(chess,c);               //输出棋盘当前皇后情况

            //printf("status is %d\n\n",reasonalbe(chess));

            /*开始分类讨论*/

            if(reasonalbe(chess) == 0 && k == 7)            //1、八皇后问题解决
            {
                printf("八皇后问题得到深度优先解\n\n");
                printf("解向量为:");
                print_c(c);
                printf("\n");
                flag = 1;                                  //问题解决,直接退出算法
                break;
            }

            else if(reasonalbe(chess) == 0 && k < 7)       //2、得到部分解
            {
                printf("这是部分解,继续\n\n");
                k = k + 1;
                break;
            }

            else if(reasonalbe(chess) == 1 && c[k] < 7)    //3、新放的皇后和已有的冲突
            {
                printf("碰到冲突,尝试同行下一个\n\n");
                continue;
            }

            else if(reasonalbe(chess) == 1 && c[k] == 7)   //4、一行皇后试到底,无路可走
            {
                printf("开始回溯\n\n");
                c[k] = 0;
                k = k - 1;
                continue;
            }

            else if(c[k] > 8)                              //5、回溯后如果再碰到回溯
            {
                printf("开始多重回溯\n\n");
                c[k] = 0;
                k = k - 1;
                continue;
            }
        }
    }

    if(flag == 1)                                          //6、如果问题解决,输出皇后棋盘
        printchess(chess,c);
    else
        printf("no solution!\n\n");

}

int reasonalbe(int chess[8][8])                           //判断是否可以放皇后
{
    int flag = 0;
    int number = 0;
    int i,j,k;

    for(i = 0;i < 8;i++)                                  //行扫描,判断每一行是否有两个皇后
    {
        for(j = 0;j < 8;j++)
        {
            if(chess[i][j] == 1)                          //如果有皇后,计数器number+1
            {
                number ++;
                //printf("%d,%d\n",i,j);
            }
        }

        if(number > 1)                                    //如果每行多于一个皇后
        {
            flag = 1;                                     //标志位设置为1,退出判断
            i = 8;
            break;
        }
        number = 0;                                       //计数器归0,进行下一行判断
    }


    for(i = 0;i < 8;i++)                                  //列扫描,判断每一列是否有两个皇后
    {
        for(j = 0;j < 8;j++)
        {
            if(chess[j][i] == 1)                          //如果一列上有皇后,计数器+1
            {
                number ++;
                //printf("%d,%d\n",j,i);
            }
        }

        if(number > 1)                                    //原理和行类似,不再阐述
        {
            flag = 1;
            i = 8;
            break;
        }

        number = 0;
    }


    for(i = 7;i >= 0;i--)                                 //斜扫描1,扫描区域为主对角线以下的每一个斜列
    {
        for(j = 0;i + j <= 7;j++)
        {
            if(chess[i + j][0 + j] == 1)
            {
               number ++;
               //printf("%d,%d\n",i+j,j);
            }

        }

        if(number > 1)                                    //原理和之前行列类似
        {
            flag = 1;
            i = 8;
            break;
        }

        number = 0;
    }

    for(k = 0;k <= 7;k ++)                                //斜扫描2,扫描区域为副对角线下方区域
    {
        for(i = 7 - k,j = 7; i <= 7; i++,j--)
        {
            if(chess[i][j] == 1)
            {
                number ++;
            }
        }

        if(number > 1)
        {
            flag = 1;
            i = 8;
            break;
        }

        number = 0;
    }

    for(k = 0;k <= 7;k++)                                //斜扫描3,扫描区域为主对角线上方区域
    {
        for(i = 0,j = 7 - k;j <= 7;i++,j++)
        {
            if(chess[i][j] == 1)
            {
                number++;
            }
        }
        if(number > 1)
        {
            flag = 1;
            i = 8;
            break;
        }

        number = 0;
    }

    for(k = 0;k <= 7;k++)                                //斜扫描4,扫描区域为副对角线上方区域
    {
        for(i = 0,j = k;j >= 0;i++,j--)
        {
            if(chess[i][j] == 1)
            {
                number++;
            }
        }
        if(number > 1)
        {
            flag = 1;
            i = 8;
            break;
        }

        number = 0;
    }

    return flag;
}

void printchess(int chess[8][8],int c[8])
{
    int i,j;
    printf("当前的棋盘的情况如下所示:\n\n");
    for(i = 0;i <= 7;i ++)
    {
        for(j = 0;j <= 7;j ++)
        {
            if(chess[i][j] == 1)
                printf("■");
            else
                printf("□");
        }

        printf("\n");
    }

    printf("\n");
}

void putchess(int chess[8][8],int c[8])
{
    int i,j;


    for(i = 0;i < 8;i++)                            //放置棋子前,先全部初始化
        for(j = 0;j < 8;j++)
            chess[i][j] = 0;


    for(i = 0;i < 8;i ++)                           //根据解向量进行放棋子
    {
        if(c[i] != 0)
            chess[i][c[i] - 1] = 1;
    }
    printf("\n");
}

void print_c(int c[8])
{
    for(int i=0;i<8;i++)
        printf("%d  ",c[i]);
    printf("\n");
}

 

  • 3
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值