C学习---递归回溯法解决八皇后问题

继上次学完函数之后,这次来通过一个实例来加深印象,下面会对其实现过程进行一一剖新,先看一下什么叫“八皇后问题”

具体的算法可以分解为:

像上图中第五行就已经出现了死胡同,这时应该退到第四行,重新安放皇后:

了解了算法流程,下面一步一步来实现:

第一步:

#include <stdio.h>

#define QUEEN_NUM 8
int queen[QUEEN_NUM];

// 在第y行上放置皇后
void place(int y);

int main(void)
{
    place(0);//首先从第1行开始放置
    return 0;
}

void place(int y)
{
    
}

说明一下queen[QUEEN_NUM]数组的含义:

queen[0] = 3代表该皇后y轴的坐标为0,x轴的坐标为3;

queen[1] = 5代表该皇后y轴的坐标为1,x轴的坐标为5;

这样用一个一维数组就可以表达八皇后的问题。

第二步:

#include <stdio.h>

#define QUEEN_NUM 8
int queen[QUEEN_NUM];

// 在第y行上放置皇后
void place(int y);
// 检测在第y行第x列能否放置皇后
int check(int y, int x);
void show();

int main(void)
{
    place(0);
    return 0;
}

void place(int y)
{
    if (y == 8)//直接显示八皇后坐标
    {
        show();
        return;
    }

    int i;
    for (i=0; i<QUEEN_NUM; i++)    // 在第y行的每一列上试探
    {
        if (check(y, i))
        {
            queen[y] = i;
            place(y+1);    // 在下一行放置皇后
        }
    }

    
}

第三步:实现判断是否坐标点能否放置皇后的方法

#include <stdio.h>

#define QUEEN_NUM 8
int queen[QUEEN_NUM];

// 在第y行上放置皇后
void place(int y);
// 检测在第y行第x列能否放置皇后
int check(int y, int x);
void show();

int main(void)
{
    place(0);
    return 0;
}

int check(int y, int x)
{
    int i;
    for (i=0; i<y; i++)
    {
        if (queen[i] == x || y - i == abs(x - queen[i]))//如果在同一列,或是斜线上的,则不能存放
            return 0;
    }

    return 1;
}

void show()
{
    
}

void place(int y)
{
    if (y == 8)
    {
        show();
        return;
    }

    int i;
    for (i=0; i<QUEEN_NUM; i++)    // 在第y行的每一列上试探
    {
        if (check(y, i))
        {
            queen[y] = i;
            place(y+1);    // 在下一行放置皇后
        }
    }

    
}

 第四步:显示符合八皇后的坐标:

#include <stdio.h>

#define QUEEN_NUM 8
int queen[QUEEN_NUM];

// 在第y行上放置皇后
void place(int y);
// 检测在第y行第x列能否放置皇后
int check(int y, int x);
void show();

int main(void)
{
    place(0);
    return 0;
}

int check(int y, int x)
{
    int i;
    for (i=0; i<y; i++)
    {
        if (queen[i] == x || y - i == abs(x - queen[i]))
            return 0;
    }

    return 1;
}

void show()
{
    int i;
    static int count = 0;//这个只会初始化一次,所以该函数是有状态的,可以一直累加
    printf("the %d solution\n", ++count);
    for (i=0; i<QUEEN_NUM; i++)
    {
        printf("(%d, %d) ", i, queen[i]);
    }
    putchar('\n');
}

void place(int y)
{
    if (y == 8)
    {
        show();
        return;
    }

    int i;
    for (i=0; i<QUEEN_NUM; i++)    // 在第y行的每一列上试探
    {
        if (check(y, i))
        {
            queen[y] = i;
            place(y+1);    // 在下一行放置皇后
        }
    }

    
}

运行结果:总共92个解

这样打印出来不太直观,实际上可以9空格的样式打印出来:

void show()
{
    int i;
    int j;
    static int count = 0;//这个只会初始化一次,所以该函数是有状态的,可以一直累加
    printf("the %d solution\n", ++count);
    for (i=0; i<QUEEN_NUM; i++)
    {
        printf("(%d, %d) ", i, queen[i]);
    }
    putchar('\n');
    for (i=0; i<QUEEN_NUM; i++)        // 行
    {
        for (j=0; j<QUEEN_NUM; j++)    // 列
        {
            if (queen[i] == j)//代表这一个坐标为皇后,就输出Q
                printf("Q ");
            else
                printf("x ");//代表这一个坐标没有皇后,就输出X
        }
        putchar('\n');
    }
}

输出如下:

好了,今天的练习到此,至于怎么回溯的,需看代码仔细体会下。

关注个人公众号,获得实时推送

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

webor2006

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值