是数据结构的课设(@.@)
以下为全部代码:

//编译运行环境:VC++ 6.0
//win10 10.0.18362
#include <stdlib.h>
#include <stdio.h>
#include <string.h>long int fac[10] = { 1,1,2,6,24,120,720,5040,40320,362880 };//阶乘表,康托展开定位位置时会用到char step[363880] = { 0 };         // 9!=362880,记录每一种情况是否被走过char method[4][2] = { {-1,0},{0,1},{1,0},{0,-1} };   //4种移动方法struct node {char data[9];int  step_p;int way;
};struct node save_step[363880];               //保存移动数据,最多有 9!个移动数据char   endnode[9];          //终点坐标long int    end_location;          //记录终点的locationlong int locate(char s[], int n)
{int i, temp;long int num = 0;for (i = 0; i < n; i++){temp = 0;for (int j = i + 1; j < n; j++)if (s[j] < s[i])  //判断几个数小于它temp++;num += fac[n - i - 1] * temp;}return  num;
}//检查移动后的情况
int check(int i, char data[])
{int x, y;long int num;for (int j = 0; j < 9; j++)if (data[j] == 0){//计算空格移动后的坐标x = j % 3 + method[i][0];y = j / 3 + method[i][1];//判断移动后的位置是否越界if (x < 0 || x>2 || y < 0 || y > 2)return 0;//判断移动后的位置是否已走过data[j] = data[x + y * 3];data[x + y * 3] = 0;num = locate(data, 9);if (step[num] == 1)       //已被走过,也不是终点{return 0;}if (memcmp(endnode, data, 9) == 0)  //是终点{return 2;}step[num] = 1;return 1;}
}long int start = 0, end = 0;
long int bfs()
{long int next_end = end;           //next_end是走完下一步的位置,end是现在的位置int flag;char temp[9];for (; start <= end; start++){for (int i = 0; i < 4; i++)      //4种走法,依次走{memcpy(temp, (char*)save_step[start].data, 9);flag = check(i, temp);     //检查这一步走的结果if (flag)   //如果没被走过,也没越界{memcpy((char*)save_step[++next_end].data, temp, 9);save_step[next_end].way = i;                    //记录移动方向save_step[next_end].step_p = start;             //记录步数位置     if (flag == 2)  //找到终点{end_location = next_end;          //记录终点步数位置.return 1;                      //找到终点,返回1,依次递加,看一共递归了多少层}}}}start = end + 1;end = next_end;return (1 + bfs());
}int getmode(char num[])
{int count;for(int i=0; i<9; i++){for(int j=i; j<9; j++){if(num[i] > num[j])count++;}}count = count%2;return count;
}
int solvableornot()
{int startstate, endstate;startstate = getmode(endnode);endstate = getmode(save_step[0].data);if(startstate == endstate)return 1;else return 0;
}int main()
{long int count = 0;         //步数system("color a");//输入int i;printf("请输入起点九宫格:\n");for (i = 0; i < 9; i++){scanf("%1d", &endnode[i]);}printf("请输入目标九宫格:\n");for (i = 0; i < 9; i++){scanf("%1d", &save_step[0].data[i]);}//判断是否有解int solvable = solvableornot();          if(!solvable){printf("unsoloved\n");exit(1);}//求解count = bfs();printf("共需要%d步\n依次为:\n", count);long int tempend=end_location;int tempcount;for (tempcount = 0; tempcount < count; tempcount++){switch (save_step[tempend].way){case 0:printf("右"); break;case 1:printf("上"); break;case 2:printf("左"); break;case 3:printf("下"); }tempend = save_step[tempend].step_p;}printf("\n按任意键开始动态演示");system("pause >nul");//依次输出每一步for (tempcount = 0; tempcount <= count; tempcount++){system("cls");printf("第%d/%d步\n", tempcount,count);printf("\t+———————+\n");printf("\t|  %d |  %d |  %d |\n", save_step[end_location].data[0], save_step[end_location].data[1], save_step[end_location].data[2]);printf("\t|———————|\n");printf("\t|  %d |  %d |  %d |\n", save_step[end_location].data[3], save_step[end_location].data[4], save_step[end_location].data[5]);printf("\t|———————|\n");printf("\t|  %d |  %d |  %d |\n", save_step[end_location].data[6], save_step[end_location].data[7], save_step[end_location].data[8]);printf("\t+———————+\n");end_location = save_step[end_location].step_p;printf("\n");system("pause");}printf("演示结束,按任意键退出");system("pause >nul");return 0;
}

以下从主函数开始对每个部分进行详细讲解:

变量count用来存储求解出的步数
system(“color a”);是终端命令,将字题颜色变成淡绿色
i用于循环
下面的两个循环分别用于输入起点和终点,(为了显示路径方便)其中endnode是终点,save_step[0].data[]是起点。
save_step[]数组的定义可以在前面找到,这是一个结构体数组,用于存储每一个步的信息。其中每一个数据存储的内容包括:data[9]:此步的九宫格;step_p:此步的位置;way:此步的移动方向;

输入结束后,判断此九宫格问题通过移动是否可解:
solvable用于表示问题可解与否;
调用solvableornot()函数进行判断;
solvableornot()的原理涉及到高等代数中排列的相关知识,详细请参考:https://wenku.baidu.com/view/d68955a0aef8941ea76e05ed.html
在solvableornot()函数中,startstate变量表示起始点为奇排列还是偶排列,endstate表示终点为奇排列还是偶排列。分别经getmode()函数判断后,根据排列的对换相关知识,若两者相同,则有解,返回1。反之则无解,返回0;

回到主函数,无解则输出无解并退出,有解则进入bfs()函数进行计算。

bfs()函数上面定义的start和end用于表示位置。函数中的next_end用于表示
第一层循环依次取需要遍历但还未遍历的步的位置,第二层循环走出上下左右这四步。
memcpy函数将走出一步前九宫格的内容传递给temp[];然后用check()函数判断这一步的情况.

跟进check()函数;首先用x,y来表示移动后0(即空格)的坐标,然后判断此次移动是否出界。若出界,直接返回0,表示此次移动不合法。之后的几行,判断此位置是否已经走过了,

跟进locate函数;此函数使用康托展开,用于定位传入的参数在所有0~8九个数字的排列组合中排的顺序,也就是在step[]数组中应占的位置(step[]数组的定义可以在前面找到,用于表示对应位置是否已被访问)。并将这个位置返回。
康托展开可参考:https://baike.baidu.com/item/%E5%BA%B7%E6%89%98%E5%B1%95%E5%BC%80/7968428?fr=aladdin

回到check()函数;判断step[num]是否为1,若为1则表示该结点已被访问过,此路径可抛弃,并返回0;若未访问过,则判断此节点是否为终点,是则返回2;不是则将该结点的标志置1,表示已访问,并返回1;

回到bfs()函数;若此次移动合法,则将此次移动后的信息记录到存储每一步信息的结构体数组save_step[]中;若找到终点,则返回1,每次递归都返回1,最终主函数中调用的bfs()就将返回递归的层数,也就是步数。
若不是终点,就将start和next_end都置为下一个需要遍历但还未遍历的结点,然后递归调用bfs(),进行下一次移动。
最终找到终点,返回1,并在每一次返回时+1,最终返回到主函数,就是一共走的步数。

PS
step[]数组用于存储对应的结点是否已经走过,由于0-8所有数的排列组合一共有9!种情况,所以要有9!个元素。

如果我有任何理解错误的地方,还请大佬不吝指出!


向大佬低头.gif

九宫格重排问题 代码及通俗讲解相关推荐

  1. 蓝牙聊天App设计3:Android Studio制作蓝牙聊天通讯软件(完结,蓝牙连接聊天,结合生活情景进行蓝牙通信的通俗讲解,以及代码功能实现,内容详细,讲解通俗易懂)

    前言:蓝牙聊天App设计全部有三篇文章(一.UI界面设计,二.蓝牙搜索配对连接实现,三.蓝牙连接聊天),这篇文章是:三.蓝牙连接聊天. 课程1:Android Studio小白安装教程,以及第一个An ...

  2. Hadoop平台K-Means聚类算法分布式实现+MapReduce通俗讲解

        Hadoop平台K-Means聚类算法分布式实现+MapReduce通俗讲解 在Hadoop分布式环境下实现K-Means聚类算法的伪代码如下: 输入:参数0--存储样本数据的文本文件inpu ...

  3. 关于CSS浮动(float,clear)的通俗讲解(经验分享)

    很早以前就接触过CSS,但对于浮动始终非常迷惑,可能是自身理解能力差,也可能是没能遇到一篇通俗的教程. 前些天小菜终于搞懂了浮动的基本原理,迫不及待的分享给大家. 写在前面的话: 由于CSS内容比较多 ...

  4. Java多数据源最通俗讲解

    Java多数据源最通俗讲解 before after 理论 实操 编码 小总结 before 项目中可能会用到很多的数据源,例如目前这个项目中用到了五个数据源,那么数据源的 配置和数据源的切换就成为了 ...

  5. 网络编程懒人入门(九):通俗讲解,有了IP地址,为何还要用MAC地址?

    1.前言 标题虽然是为了解释有了 IP 地址,为什么还要用 MAC 地址,但是本文的重点在于理解为什么要有 IP 这样的东西.本文对读者的定位是知道 MAC 地址是什么,IP 地址是什么. (本文同步 ...

  6. Linux账户标识R=400是什么意思_带你阅读linux内核源码:通俗讲解编译器、交叉编译器和大小端...

    欢迎关注"技术简说",持续分享linux内核和驱动开发干货. 本文内容包括: 编译器和交叉编译器的介绍 交叉编译器的命名规则 如何交叉编译C代码 大端.小端的通俗讲解 如何判断你的 ...

  7. CSS浮动(float,clear)通俗讲解- 杨元- 博客园

     学习CSS布局 主页目录 inline-block 你可以创建很多网格来铺满浏览器.在过去很长的一段时间内使用 float 是一种选择,但是使用 inline-block 会更简单.让我们看下使用这 ...

  8. 通俗讲解:PoW共识机制与以太坊的关系、Ghost协议 及 Casper PoS共识机制的变种...

    作者:林冠宏 / 指尖下的幽灵 掘金:juejin.im/user/587f0d- 博客:www.cnblogs.com/linguanh/ GitHub : github.com/af9133374 ...

  9. 通俗讲解:PoW共识机制与以太坊的关系、Ghost协议 及 PoS共识机制的变种---Casper...

    作者:林冠宏 / 指尖下的幽灵 掘金:https://juejin.im/user/587f0dfe128fe100570ce2d8 博客:http://www.cnblogs.com/linguan ...

最新文章

  1. 代码简介:向圣诞老人和他的精灵学习Google Analytics(分析)
  2. mysql教程左右链接_mysql的左右内连接用法实例
  3. Oracle11gR2 数据库客户端PL/SQL中文乱码的问题
  4. 从零开始发布前端代码到服务器上_无服务器计算:让每行代码都能住上“经济适用房”...
  5. 深入解析NoSQL数据库的分布式算法
  6. how to collect staff from lovespace
  7. jbpm 和 drools_jBPM和Drools工作台中的用户和组管理
  8. 用数据库修改服务器的时间格式,如何查询数据库服务器的时间格式
  9. 虚拟跳线软件干什么用的_疯狂刷单!用违法软件生成虚拟手机号,“骑手”半年“刷单”牟利60余万,百米内竟有万笔订单 | 申晨间...
  10. 百度邓凯鹏:飞桨视觉技术解析与应用
  11. python解析mht文件_php解析mht文件转换成html的实例
  12. spark scala求PV,UV,topN
  13. win10去掉快捷方式小箭头_win7电脑桌面图标有这样的小箭头,怎么去掉?
  14. RNN(pytorch)的维度问题——用GRU实现文本分类(参考刘二大人)
  15. 【前端作业系列】HTML基础点 , 训练<有序列表><无序列表>(2022年6月15日作业)
  16. #使用SAS进行变量筛选、模型诊断、多元线性回归分析 #
  17. C++包含文字时的输出排版问题
  18. python twisted教程_twisted基础教程.pdf
  19. 计算机进制与信息编码,信息与二进制编码
  20. 手把手教你,把3D模型从stl格式导出iges格式的方法

热门文章

  1. win7驱动备份_彻底解决WIN7宽带连接错误651问题的办法
  2. 全国计算机等级考试的照片怎么弄啊?
  3. haproxy配置TCP代理
  4. 网易云音乐背景高斯模糊探索
  5. 网站建设中如何选择域名?新域名or老域名?
  6. Spark RDD(三)
  7. 第三代酷睿i3处理器_中秋国庆同天百年罕见 十代酷睿轻薄本助力出行
  8. matlab实现cqt频谱,LPCC、MFCC和CQCC简介及matlab实现
  9. 加密文件的识别和破解工具—比elcomsoft更适合中国市场的密码破解工具—掘密
  10. 【专业选择】想选择 IT 相关专业?那么就要先详细了解 IT 行业!