华容道问题求解_详细设计(三)之查找算法1_DFS

(续上篇)
使用DFS查找算法的原因是因为它符合本人的思考习惯,另外在第一版时用的就是这个方法,后来知道这不是查找这类问题的最好方法。
在前面的概要设计中的框图里描述的方法就是DFS,它可以找到一个解法,时间可能比较快。(不一定,看运气)

DFS算法基本要素分析

DFS 深度优先算法,核心是采用堆栈结构存贮中间过程。其特点是后进先出,从而也决定了其所谓深度优先的特点。即后续情形都是最先处理,因此就会沿着一条路径探索下去,到达终点后,才返回去处理没有处理过的。画出图来,它的过程就像一个触角一样,伸到最远处,再回退继续执行类似的过程,不但探索知道全部探索结束。

堆栈操作分析

 堆栈中应该保存一个当前的布局,如图示:
 这是初始布局
 ![在这里插入图片描述](https://img-blog.csdnimg.cn/direct/1e773af73fd346c3ac5d062745e2ddc7.png)
 移动一个棋子如下
 ![在这里插入图片描述](https://img-blog.csdnimg.cn/direct/c9e3023e86ef4afa9035c4768c220519.png)
 假设此时不能继续移动,那么应该返回到上一个场景;也就是说在移动棋子之前,初始布局需要入栈,到当前的无路可走状态(假设),需要做出栈处理。出栈后,需要恢复之前的布局,也就是棋子的位置。因此必须要引入当前布局的一个快照,我这里称之为状态,同时为了便于对相同的局面进行判断,也需要引入一个当前局面的指纹作为记录。当然这个指纹可以是一个hash 值。
 经过上述分析,我们要得到当前布局的快照和一个hash 值用来记录这个快照。
 说明:非常容易犯一个错误,就是把当前的布局实例进行入栈操作,这个看起来好像很对,但是实际上由于入栈操作对对象而言,保存的是一个引用,因此后续操作会影响堆栈里的那个保存的对象属性(其实就是同一个实例而已)。因此必须要克隆一个当前布局的实例,将这个克隆的实例入栈。另外在出栈时,还要将它映射回去到当前的布局中。
 根据上面的思路,有关堆栈相关的代码如下:
 首先,在设置初始布局的函数中的最后部分,进行了堆栈的初始化
     private void _setDefayultLayout()
     {
    	......

         //CurPiece = _gameState.pieces[0];
         // push the initial state onto the  stack 
         SearchOpenPieces(); // 查找可以移动的棋子
         StateShot stateShot = new StateShot(gameState, 0);//克隆当前局面的快照
       
         var stVertexLst = new List<Piece>{ gameState.pieces[2],gameState.pieces[3], gameState.pieces[4], gameState.pieces[5] };//记录可能的起始节点,这里指的是图结构的起点,后面会述及。
         //################################################
         //##                 初始化堆栈                  ##
         //################################################
         
         InitStateStack(stateShot, stVertexLst);//初始化堆栈
     }

为了提高效率,先找到可以移动的棋子,即 open piece,把这个数据也保存到堆栈中,这样出栈后,就不用再计算了。

构造一个图

因为DFS找到的结果不一定是最佳方法,因此要想办法找到求解最佳路径的方法。理论上,上面的算法应该是遍历了所有的场景,如果把这些场景看做是一个节点那么可以想见这个查找方法实际上是可以构造出一个图来的。只要知道起始点和终点,利用现有的最短路径算法,例如 Dijkstra 算法,就可以找到最佳方法(最短路径)。因此下面的问题是如何建立这个图。
图的两个要素,一个是节点一个是路径。显然节点可以考虑用每个布局的hash 值来表示,而路径是两个节点确定的,如果是加权路径,还有个路径的长度。在华容道的经典步骤中,实际上是不考虑路径长度的。只考虑动作,不考虑这个动作的开销,因此在这个图中如果按照传统的手工走法,只要将每条路径的权重设为一样就可以利用最短路径算法找出来和人工移动一致的最佳步数。如果权重不一样,例如将移动一格(一个单位正方形)的权重设为1, 移动两格的权重设为2,利用最短路径算法就可以找出来移动距离最少的解法(有人把这种方法算作是最佳方法)。
构造一个图的具体步骤,在堆栈的进出过程中,有一步是必须要做的,就是重复步骤的判断。可以想见,如果移动时,碰到重复的走法,这个走法应该放弃,否则就会陷入死循环当中。用图来考虑,就是这个节点已经存在了,但是路径应该是新的,因此对于重复的布局,只要将路径加上就可以了,这样到全部步骤结束(栈空)时,这个所有节点和路径就都有了,图的数据结构也就建好了。
另外,华容道的解法布局,我们是知道的,即 曹操的在出口的位置就是完成了一个解;然而此时其他棋子的位置我们是不知道,因此在构造图的终点节点时,需要做个特殊判断。
根据上述分析,得到如下代码

    /// <summary>
    ///  Used to create a graph data structure 
    /// </summary>
    /// <returns></returns>
    internal bool CreateGraph()
    {
        //1# pop from the stack for the first step , note:The initial state must be pushed to the stack!!!!!
        if (statesObjStack.Count == 0) return false;
        var lastState = PopState();
        //var lastHashCode=   layoutHashCodeStk.Pop();

        // map it to the current  state 
        MapToCurState(lastState);

        //Check if all of the open pieces have been moved 
        if (gameState.openPieces.Count > 0 && gameState.curOpenIdx < gameState.openPieces.Count)// There are open pieces not moved , move them one by one.
        {
          //移动一个棋子
          // 确定移动的棋子以及移到到哪个空白区域上
            var selOpenPcs = gameState.openPieces[gameState.curOpenIdx];
            var selPcs = selOpenPcs.piece;
            var toPcs = selOpenPcs.MoveToPcs;
          //移动这个棋子
            var dirFrom = MoveToPcs(selPcs, toPcs);
            gameState.selPcs = selPcs;
            //判断这个布局是否重复
            var redundant = RedundantState(gameState);
            StateShot stateShot = new StateShot(gameState, 0);
            //Create the graph data structure 
            //构造这个图
            AddEdgeToGraph(lastState, stateShot);

            if (redundant.Item1)// return to last layout 
            {
                MapToCurState(lastState);
 
            }
           
			//判断是否所有的open pieces已经走完
            if (gameState.curOpenIdx < lastState.openPcsArr.Length)
            {
                //push it again to the stack
                gameState.curOpenIdx++;
                lastState.lastOpenIdx = gameState.curOpenIdx;
                PushState(lastState);
             }
   
            //check if the current is a redundant one, it it is , return to last layout that going to pop the stack 
    
            if (!redundant.Item1)
            {
                //push the current state to stack 
                //SearchOpenPieces(selPcs, dirFrom);
                SearchOpenPieces();
                //StateShot lastShot = new StateShot(lastState, 0);
                stateShot = new StateShot(gameState, 0);
                PushState(lastState, stateShot,selPcs, toPcs);//add edge to the grapph 
            }
            // Judge if it succeeds that caocao is at the exit of the board.
            
         //############################################################################
         //### 判断曹操是否出来,并且计算当前的hash值,记住这个节点,保存到终点集合中。 ###
         //############################################################################
         
            if (selPcs.type == HRDGame.TYPE_BIG_PIECE )
            {
                if (selPcs.hrdPos.X == 2 && selPcs.hrdPos.Y == 4)
                {
                    RefreshLayout();
                    Application.DoEvents();
                    var verTex = GetMyHashCodeV1(gameState);
                    // the layout might not the same that needs to record all of them 
                    if (!endVtxLst.Contains(verTex)) endVtxLst.Add(verTex);
                  }
            }

        }

        return true;

    }

上述程序运行结束后,我们要的图就构造好了,同时也会找到一定数目的解法,这个解法大概率不是最优的。最后调用最短路径算法,就可以找到最佳步骤。
图的构造,采用一个数据字典,定义如下:

       Dictionary<int, (int,int)> hCodeAndShotShortPathDict = new Dictionary<int, (int,int)>();// key:the hash code of the current layout, value.item1, the hashcode of the source layout , item2 the number of the shortest steps.

注意,上面使用了 C# 的tuple类型。字典变量的Value 值的第二项就是路径的权重,这里都设定为1,实际上相当于无权图。
构造图的关键函数代码如下:

       private void AddEdgeToGraph(StateShot source, StateShot dest)
       {
          //计算起终点的hash值
           var toHashCode = GetMyHashCode(dest);
           var frmHashCode = GetMyHashCode(source);
           AddEdge(frmHashCode, toHashCode, 1);
       }

其中

        public void AddEdge(int source, int dest, int weight)
        {
            if (!adjacencyList.ContainsKey(source))
            {
                AddVertex(source);
            }

            if (!adjacencyList.ContainsKey(dest))
            {
                AddVertex(dest);
            }

            if(!adjacencyList[source].Contains((dest, weight))){
                adjacencyList[source].Add((dest, weight));
            }
            if (!adjacencyList[dest].Contains((source, weight)))
            {
                adjacencyList[dest].Add((source, weight));
            }
            //adjacencyList[dest].Add((source,weight)); // Uncomment this line if the graph is undirected
        }

注意这个图是无向图。
另:这个图的构造和Dijkstra解法均来自ChatGPT
图构造好之后,调用 Dijkstra 方法,得到了最优解,这个步骤和公认的81步是一致的,因此这也间接证明了上述方法的正确性。
实际上找到了好几种不同的符合结果的布局,其中最少的一步是 81步。结果截图如下
结果布局1
结果布局1
结果布局2
在这里插入图片描述
结果布局3
在这里插入图片描述
还有几种从略。
简单讨论
由于开局是对称的,因此结果的布局结果应该也是对称的,但是最终笔者的算法结果并不是对称的。思考一下原因,是在求解过程当中,对于重复节点的判断应该导致没有出现对称结果的原因。但是这并不妨碍图的构造。如果将这个图画出来,它应该是一个对称的图形。
最终81步的结果截图如下:
在这里插入图片描述
演示过程如下

华容道81步演示_CSDN

这个是笔者最早找到的方法,是一个综合应用,但是效率不高,时间也比较长。而在采用了BFS之后,不但效率提高很多,也找到了对称的结果集,将在后续篇章介绍。

MaraSun BJFWDQ
2014-03-07

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/437199.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

某省内存取证真题详解

需要环境的私我 题目描述: 一,从内存中获取到用户admin的密码并且破解密码,以Flag{admin,password}形式提交(密码为6位) 二,获取当前系统ip地址及主机名,以Flag{ip:主机名}形式提交; 三,当前系统中存在的挖矿进程,请获取指向的矿池地址,以Flag{ip}形式提交 四,恶意进…

大数据冷热分离方案

数据冷热分离方案 1、背景 ​ 随着业务的发展&#xff0c;在线表中的数据会逐渐增加。常规业务都有冷热数据现象明显的特性&#xff08;需要访问的都是近期产生的热数据&#xff1b;时间久远的冷数据出于备份、备案溯源等诉求会进行在线保留&#xff09;。在业务表数据 量可控…

问题总结,web自动化测试元素无法操作?shadowDOM节点元素解决......

前言 web自动化遇到shadowDOM你会操作吗&#xff1f; 之前在做web自动化的时候&#xff0c;发现页面上有些元素&#xff0c;在selenium中无法通过xpath来定位&#xff0c;各种原因找了半天都没找到解决方案&#xff0c;最后发现元素在一个叫做shadow-root的节点下面&#xff…

艺术与科技的结合,AI绘画图生图怎么样?

AI绘画图生图是指通过人工智能技术生成的具有艺术价值的图像。它可以根据用户提供的参考图像或描述&#xff0c;自动生成具有艺术风格的新图像。这些图像可以是风景、人物、抽象画等各种形式。那么ai绘画图生图到底怎么样&#xff1f; AI绘画图生图的优点在于它可以快速、高效地…

R语言安装IDE工具,RStudio 安装

R语言安装IDE工具&#xff0c;RStudio 安装 介绍下载安装包安装使用运行结果快捷键和使用技巧常用快捷键使用技巧 介绍 RStudio是一个集成开发环境&#xff08;IDE&#xff09;&#xff0c;专门用于R编程语言的开发和数据分析。它提供了许多工具和功能&#xff0c;使R编程更加…

初始网络 --- 网络基础

目录 0、 前言 1、 计算机网络发展背景 1.1. 局域网(LAN) && 广域网(WAN) 2、 认识并理解协议 3、 初始网络协议 3.1. 协议分层 4、 TCP/IP 五层(或四层)模型 4.1. 简单了解TCP/IP层状体系 4.2. TCP/IP协议层状结构和计算机层状结构的关系 5、 OSI七层模型 …

七.AV Foundation 视频播放 - 图片进度条

引言 播放器的功能功能已经十分完善了&#xff0c;接下来我们给它添加一些提升用户体验的功能。当前市面上的主流播放器几乎都有一个非常友善的功能&#xff0c;用户在退拽进度条的时候可以看见进度条所处进度的视频画面&#xff0c;这对于用户来说是一种直观而且便捷的体验。…

noetic ros配置因时机械夹爪的驱动

noetic ros配置因时机械夹爪的驱动文件 配置编译教程解决方案 配置编译教程 1.inspire_robot 包支持因时机器人公司的机械夹爪在ROS平台上的使用&#xff0c;我们在ros noetic环境下进行了测试。 2.为了使程序能够正常运行&#xff0c;需要执行以下环境配置操作&#xff1a;&a…

php:下拉列表查询(静态数据+数据库数据)

一、在php中嵌套 效果 1、从php中嵌套html语句 下拉列表的显示 echo <div class"text-nav-1 required "><div> . _(在职状态) . :</div> <select name"work_status">; // 定义选项数组 $options [all > _(全部),inwork &g…

越南电力展|2024年第17届越南国际电力设备与技术展览会

2024年第17届越南国际电力设备与技术展览会 The 17th International Exhibition on ELECTRICAL TECHNOLOGY & EQUIPMENT VIETNAM ETE 2023 同期举办&#xff1a;2024 年第 14 届越南节能和绿色能源科技产品博览会 The 14th International Exhibition on PRODUCTS TECHNO…

C语言--- qsort函数

目录 一.qsort函数 1.qsort函数的功能 2.四个参数讲解 (1)base (2)num (3)size (4)compare 3.使用qsort函数对一个整形数组进行排序 4.qsort函数排序结构体数据 第一种&#xff1a;按照年龄进行比较 第二种&#xff1a;按照名字进行排序 二.利用冒泡排序模仿qsort函…

慢sql优化记录1

慢sql为&#xff1a; select count(*) from t_wf_process p left join t_wf_core_dofile dofile on p.wf_instance_uid dofile.instanceid join zwkj_department d on p.userdeptid d.department_guid ,t_wf_core_item i,wf_node n where (p.IS_DUPLICATE ! true or p.IS_DU…

Leetcoder Day39| 动态规划part06 完全背包问题

完全背包理论 有N件物品和一个最多能背重量为W的背包。第i件物品的重量是weight[i]&#xff0c;得到的价值是value[i] 。每件物品都有无限个&#xff08;也就是可以放入背包多次&#xff09;&#xff0c;求解将哪些物品装入背包里物品价值总和最大。 示例&#xff1a; 背包最大…

2023第二届陇剑杯网络安全大赛 SS Writeup

sevrer save_1 打开流量包文件过滤http流量 从这个/helloworld/greeting开始追踪TCP流 直接百度搜索payload 搜索得到这题flag就是CVE-2022-22965 sevrer save_2 追踪TCP流&#xff0c;在tcp.stream eq 106&#xff0c;发现反弹shell的IP和端口 这题flag为192.168.43.128:2333…

PPT模板一键下载,原创精美,2024必备!

1. PPT模板分享 &#xff08;1&#xff09;计算机学院毕业答辩PPT &#xff08;2&#xff09;开学典礼活动策划方案PPT &#xff08;3&#xff09;新员工入职培训PPT &#xff08;4&#xff09;宠物行业分析报告PPT &#xff08;5&#xff09;机关青年干部述职PPT 以上PPT模板均…

centos离线安装 k8s (实操可用)

全部安装包rpm下载&#xff08;已整理好k8s和docker&#xff09;&#xff1a;链接&#xff1a;https://pan.baidu.com/s/1ATv8BPijhvIKWz4hMnkx6Q?pwdt5db 提取码&#xff1a;t5db 将文件下载以后&#xff0c;解压到服务器 #执行所有docker-rpm包 yum -y localinstall *.rpm…

testvue-个人中心

header.vue(右上角) <template><div class="header"><!-- 折叠按钮 --><div class="collapse-btn" @click="collapseChage"><i v-if="!collapse" class="el-icon-s-fold"></i><…

实现大华摄像头的抓图-使用HTTP方式

实现抓图&#xff0c;网上大部分都是使用SDK二次开发的&#xff0c;HTTP接口实现的基本没有介绍&#xff0c;好像官方叫CUI接口&#xff0c;但是找官方要文档&#xff0c;基本要不到&#xff0c;我自己下载了一份以前的文档&#xff0c;可以做大部分操作&#xff0c;这里免费分…

【MySQL】用户管理 -- 详解

如果我们只能使用 root 用户&#xff0c;这样存在安全隐患。这时就需要使用 MySQL 的用户管理。 一、 用户 1、用户信息 MySQL 中的用户都存储在系统数据库 MySQL 的 user 表中。 字段解释&#xff1a; host&#xff1a;表示这个用户可以从哪个主机登陆&#xff0c;如果…

哪些公司在招聘GIS开发?为什么?

之前我们给大家整理汇总了WebGIS在招岗位的一些特点&#xff0c;包括行业、学历、工作经验等。WebGIS招聘原来看重这个&#xff01;整理了1300多份岗位得出来的干货&#xff01; 很多同学好奇&#xff0c;这些招GIS开发的都是哪些公司&#xff1f;主要是做什么的&#xff1f; …