暴力美学之广度搜索求解重排九宫格问题

暴力美学之广度搜索求解重排九宫格问题


前言

本文将利用C++语言实现重排九宫的搜索算法问题,代码在**第三部分**。重排九宫问题,是人工智能领域涉及搜索策略的经典问题,即在3X3的正方形方格中排列八个元素,利用空位将其一步步移动从而寻找最优解路径的过程,其中最为常见解决这个问题的算法是广度优先算法,其优点是具有完备性。而且总是能找到最优解,缺点是面对过于复杂的情况,计算量较大,受制于计算资源。广度优先搜索算法的核心思想是按照初始节点所在的层,向下逐层遍历 ,在没有搜索完本层之前不搜索下一层。写博客也主要是为了记录强化自己所学知识。

一、搜索问题描述

重排九宫问题会给出两个九宫格,例如输入两个字符串,一个是123456780和另一个123456708,就是表示初始九宫格和终止九宫格。数字来表示九宫格上不同元素差别,也完全可以用字符代替。而0的含义很特殊 ,作为标识符指示空位置,这样我们显然不需要编程也可以发现其解如下:在这里插入图片描述
只需数字8向右移动即可完成我们的目标,那么对于更加复杂的九宫格而言其结果可能无法一眼看出,例如238104765和123804765,亦或是可能根本无解的12346780和213456780。所以编程解决类似问题可以简化人的劳动。

二、广度优先搜索算法描述

1.广度搜索流程图

在这里插入图片描述

图片引用自机械工程出版社的《人工智能导论》

2.搜索过程

OPEN表中存放刚生成的节点,而CLOSE表中存放要扩展或者已经扩展的节点,如上图所示,我们通过先将初始节点放入OPEN表中,判断是否为目标节点,如果不是,则判断其可拓展性,如果也不能扩展出新的节点,或者是拓展出的所有的节点都在CLOSE表中记录过了,舍去这个节点,仅仅将其放入CLOSE表中,继续重新在OPEN表中寻找新的节点,重复这个过程。如果找到了可以拓展的节点,那么把这个节点放入CLOSE表中,并把其拓展放入OPEN表中,反复重复上述过程就可以实现对重排九宫问题的广度优先搜索。

三、C++代码实现

// 重排九宫问题.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。
#include "pch.h"
#include <iostream>
#include <string>
using namespace std;
//定义广度搜索深度为8
int deepnum = 8;
//close表中的标记
int closenumber = 0;
//定义九宫格结构体
struct Jiugong {
    //搜索深度
    int deepnumber;
    //九宫格字符组
    char jiugongge[3][3];
 struct Jiugong*father;
};
struct Jiugong open[1000000];
struct Jiugong close[1000000];
//定义两个数组储存初始和终止九宫格状态
char start[3][3];
char final[3][3];
//定义九宫格初始状态函数
int opennumber;
//显示是否可以拓展
bool flag;
//检查是否到达结束状态
bool checked(char str[3][3],char str2[3][3]) {
    for (int i = 0; i < 3; i++) {
        for (int j = 0; j < 3; j++) {
            if (str[i][j] != str2[i][j]) {
                return false;
            }
        }
    }
    return true;
}
//判断九宫格是否已经存在
bool alreadyexit(struct Jiugong a, struct Jiugong b) {
    if (checked(a.jiugongge , b.jiugongge)) {
        return true;
    }
    else return false;
}
//寻找0所在位置
int findzero(char s[3][3]) {
    for (int i =0; i <= 2; i++) {
        for (int j = 0; j <= 2; j++) {
            if (s[i][j] == '0')
                return i*3+j;
        }
    }
}

//打印九宫格
void show(char square[3][3]) {
    int i, j;
    for (i = 0; i <= 2; i++) {
        for (j = 0; j <= 2; j++) {
                printf_s("  %c ", square[i][j]);
        }
         printf_s("\r\n");
    }
}//展示需要完成移动的路径
void ShowRequire() {
    printf_s("初始的位置为:\r\n");
    show(start);
    printf_s("终止的位置为:\r\n");
    show(final);
}
//判断是否在close表中
bool inclose(char s[3][3]) {
    return false;
    for (int m = 0; m <= closenumber; m++) {
        if (checked(s, close[m].jiugongge))
            return true;
    }
    
}
//顺序输出
void inorder(struct Jiugong*root) {
    if (root == nullptr) {
        return;
    }
    else
        inorder(root->father);
        show(root->jiugongge);
        printf_s("     ↓  \r\n\r\n");
    
}
//判断是否可扩展 
bool able(char o[3][3]) {
    if (checked(o, final)) {
        printf_s("答案已经找到%d步:\r\n\r\n", close[closenumber].deepnumber+1);
        printf_s("  初始状态:\r\n");
        inorder(&close[closenumber]);
        printf_s("  终止状态:\r\n");
        show(final);
        exit(100);
    }
    //当不在close表中时,放入open表中 
    if (!inclose(o)) {
        for (int k = 0; k <= 2; k++) {
            for (int h = 0; h <= 2; h++) {
                open[opennumber].jiugongge[k][h] = o[k][h];
            }
        }
        open[opennumber].deepnumber = close[closenumber].deepnumber + 1;
        open[opennumber].father = &close[closenumber];
        opennumber++;
        return true;
    }
}
int main()
{
    //定义两个字符串存储用户输入
    string str1, str2;
    cin >> str1 >> str2;
    //初始化九宫格条件
    int index = 0;
    for (int i = 0; i < 3; i++)
    {
        for (int j = 0; j < 3; j++)
        {
            start[i][j] = str1[index];
            final[i][j] = str2[index];
            index++;
        }
    }
    //展示问题
    ShowRequire();
    //广度优先搜索
    //把初始节点放入open表中
    open[0].deepnumber = 0;
    for (int i = 0; i <= 2; i++) {
        for (int j = 0; j <= 2; j++)
            open[0].jiugongge[i][j] = start[i][j];
    }
    opennumber = 1;    while (true)
    {
        //判断open表是否为空 
        if (!open[0].jiugongge) {
            printf_s("问题 无解在第0步停止");
            exit(100);
        }        //不为空
        else {
            while ((open[0].jiugongge[1][1] + open[0].jiugongge[2][2]) >= 1)
            {
                //将节点n放入close表中
                close[closenumber].deepnumber = open[0].deepnumber;
                for (int i = 0; i <= 2; i++) {
                    for (int j = 0; j <= 2; j++)
                        close[closenumber].jiugongge[i][j] = open[0].jiugongge[i][j];
                    close[closenumber].father = open[0].father;
                }
                //删除open表中元素
                for (int l = 0; l <= opennumber + 2; l++) {
                    open[l] = open[l + 1];
                }
                opennumber--;
                //判断节点n是否为目标节点
                if (checked(close[closenumber].jiugongge, final) == true) {
                    printf_s("答案已经找到0步:\r\n" );
                    inorder(&close[closenumber]);
                    printf_s("  终止状态:\r\n");
                    show(final);
                    exit(100);
                }
                else {
                    //拓展节点n
                    int zero = findzero(close[closenumber].jiugongge);
                    char check[3][3];
                    //向左拓展
                    if ((zero) % 3 != 0) {
                        for (int k = 0; k <= 2; k++) {
                            for (int h = 0; h <= 2; h++) {
                                check[k][h] = close[closenumber].jiugongge[k][h];
                            }
                        }
                        check[(zero / 3)][(zero % 3)] = check[zero / 3][zero%3 - 1];
                        check[(zero / 3)][(zero % 3 - 1)] = '0';
                        flag=able(check);
                    }
                    //向右拓展
                    if ((zero) % 3 != 2) {
                        
                        for (int k = 0; k <= 2; k++) {
                            for (int h = 0; h <= 2; h++) {
                                check[k][h] = close[closenumber].jiugongge[k][h];
                            }
                        }
                        check[(zero / 3)][(zero % 3)] = check[zero / 3][zero % 3 + 1];
                        check[(zero / 3)][(zero % 3 +1)] = '0';
                        flag=able(check);
                    }
                    //向上拓展
                    if ((zero) /3 != 0) {                        for (int k = 0; k <= 2; k++) {
                            for (int h = 0; h <= 2; h++) {
                                check[k][h] = close[closenumber].jiugongge[k][h];
                            }
                        }
                        check[(zero / 3)][(zero % 3)] = check[zero / 3-1][zero % 3 ];
                        check[(zero / 3)-1][(zero % 3 )] = '0';
                        flag = able(check);
                    }
                    //向下拓展
                    if ((zero) / 3 != 2) {                        for (int k = 0; k <= 2; k++) {
                            for (int h = 0; h <= 2; h++) {
                                check[k][h] = close[closenumber].jiugongge[k][h];
                            }
                        }
                        check[(zero / 3)][(zero % 3)] = check[zero / 3 + 1][zero % 3];
                        check[(zero / 3) + 1][(zero % 3)] = '0';
                        flag = able(check);
                    }
                    if (flag == true) {
                        closenumber++;
                    }
                    if (open[0].deepnumber >= deepnum) {
                        printf_s("\r\n很遗憾当前的搜索深度为%d,没有解!\r\n",deepnum);
                        exit(100);
                    }
                }
            }

        }
    }
              
                }
                    
                

代码实现的主要思路是按照流程图一步一步来,定义struct Jiugong结构体,里面定义了搜索深度deepnumber九宫格字符组char jiugongge[3][3],以及 struct Jiugong*father指向其父节点的结构体指针。搜索深度在最后if (open[0].deepnumber >= deepnum)中用于判断搜索深度是否达到目标int deepnum 从而停止运行程序,九宫格字符组 用于储存九宫格状态节点,指向父节点的指针用于成功匹配九宫格目标后回溯打印九宫格路径
代码可以直接复制粘贴于c++中使用,原理方面如果有不懂的可以推荐听慕课或者教程自学,但还是可以试试我的程序感受一下广度优先搜索算法。


四、效果展示

在这里插入图片描述
输入283104765和813204765,经发现四步可以找到最优解

总结

:以上就是今天给大家介绍的内容,本文仅仅简单介绍了九宫格排序利用C++实现广度搜索算法。

  • 7
    点赞
  • 37
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
LeetCode是一个非常受欢迎的在线程序设计题库,其中包含了各种各样的算法问题。而对称美学则是指设计或艺术作品中呈现出的对称性,使人观察时能够感受到一种平衡、和谐和美感。 LeetCode的题目往往可以看作是一个个问题,而解决这些问题算法和数据结构则可以视为对称美学的表现。 首先,LeetCode题目中常常要求我们设计对称的数据结构,例如对称的二叉树、堆、队列等等。这些对称性的设计让我们在解决问题时能够更加高效地处理数据,提高了程序的性能和稳定性。 其次,LeetCode的算法问题也常常要求我们设计对称的算法,例如字符串中的回文子串问题、数组中的最长递增子序列问题等等。这些对称性的算法设计让我们在解决问题时能够更加简洁、清晰地表达解决思路,使得我们的代码更加易读、易懂。 不仅如此,LeetCode题目中还有很多需要对称地解决问题的场景,例如求解一棵二叉树的镜像、判断一个字符串是否是回文串等等。这些对称的问题不仅仅是算法和数据结构的对称,更是让我们思考问题时能够从不同的角度出发,具备创造性和灵活性的体现。 总的来说,LeetCode对称美学体现在解决问题算法和数据结构的对称性、算法的对称性以及解决问题的多样性上。这种对称美学不仅满足了人们对美感的需求,同时也能够提高我们解决问题的能力和水平。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值