BFS实现8数码问题,思考与总结
BFS实现8数码问题,思考与总结
今天中午学习了二叉树的线索化与线索化遍历,突然有一种想实现八数码问题的冲动,因为它的初级解决方式是BFS(广度优先搜索算法)。于是我开始编程。
没想到一编就是一个下午,一直编到了晚上8点。期间出现了很多问题。
1.拷贝函数拷贝完之后,对目标对象进行的操作,会影响源对象。
原来的代码:
             ints(ints obj){//拷贝构造函数
             int i,j;
             data=new myInt[3][3];
             for(i=0;i<3;i++) for(j=0;j<3;j++){//拷贝data
                 data[i][j]=obj.data[i][j];//问题点
             }
             this.parent=obj.parent;}//拷贝父编号
修改后:
         ints(ints obj){//拷贝构造函数
             int i,j;
             data=new myInt[3][3];
             for(i=0;i<3;i++) for(j=0;j<3;j++){//拷贝data
                 data[i][j]=new myInt();
                 data[i][j].set(obj.data[i][j].get());
             }
             this.parent=obj.parent;//拷贝父编号
         }
这个问题涉及到了java的对象引用方式。在出现问题的语句上,我直接使用了“=”进行赋值,传给等号左边的相当于只是右边的指针,而不是值,因为没有用“new”新建对象。修改后,新建了对象,并且进行了传值。
2.程序能跑起来,但是一直处于循环状态,无法跑出正确的答案。
开始我按照脑海里的“BFS是树的按层遍历”来编制代码。写完后发现出现了问题。
原先的代码:
         while(front<rear){
             int lastRear=rear;                        //临时队尾
             for(int i=front;i<lastRear;i++){        //树的按层遍历。对当前层全部执行出队操作。
                 ints tmp=queue.get(front++);        //出队
                 //对这个出队节点进行四个方向上的变换,构造出新的叶子节点,让他们入队
                 for(int j=0;j<4;j++){                //进行4个方向上的变换
                     ints node=new ints(tmp);        //拷贝出新的结点
                     if(node.Move(j) && (!FindInQueue(node)) ){        //如果变换成功 并且这个结点在队列中是新的
                         node.parent=front-1;
                         if(node.FindTarget(target)){
                             System.out.println("找到");
                             System.out.println(node);
                             return;        //找到目标,跳出循环
                         }
                         queue.add(node);
                         rear++;                        //入队
                         System.out.println(node);
                     }
                 }
             }
         }
按层遍历是试用一个队列,首先根节点入队,然后由根节点派生出叶子节点入队,遍历每一层,使树一层一层增加,进行遍历。
java源码
 import java.util.*;
 public class demo {
     public demo() {
         // TODO Auto-generated constructor stub
     }
     public static void main(String[] args) {
         EightNumProblem proble=new EightNumProblem();
         proble.solve();
     }
 }
 class EightNumProblem{
     int source[][] ={{1,2,3},{4,5,0},{6,7,8}};//构造一个二维 3 * 3 数组【源数据】
     int target[][] ={{1,2,3},{4,5,6},{7,8,0}};//构造一个二维 3 * 3 数组【目标数据】
     class myInt{
         int i=0;
         int get(){return i;}
         void set(int in){i=in;}
         myInt(){}
         myInt(int in){i=in;}
     }
     class ints{            //解决问题的数据结构。
         protected myInt[][] data=new myInt[3][3];//内部数据
         protected int parent;//父编号,用于回溯
         ints(){
         }
         ints(ints obj){//拷贝构造函数
             int i,j;
             data=new myInt[3][3];
             for(i=0;i<3;i++) for(j=0;j<3;j++){//拷贝data
                 data[i][j]=new myInt();
                 data[i][j].set(obj.data[i][j].get());
             }
             this.parent=obj.parent;//拷贝父编号
         }
         ints(int[][] in){
             int i,j;
             for(i=0;i<3;i++) for(j=0;j<3;j++) data[i][j]=new myInt(in[i][j]);
         }
         int get(int i,int j){
             return data[i][j].get();
         }
         void set(int i,int j,int in){
             data[i][j].set(in);
         }
         public String toString(){//重写用于打印
             int i,j;
             String re=new String("");
             for(i=0;i<3;i++){
                 for(j=0;j<3;j++){
                     re+=Integer.toString(data[i][j].get());
                     if(j!=2) re+=",";}
                 re+="\n";
             }
             return re;
         }
         void FindPos(int target,myInt X,myInt Y){//寻找目标元素,并传指 X、Y 返回。
             int i,j;
             for(i=0;i<3;i++) for(j=0;j<3;j++) if(target==data[i][j].get()){//循环,找到目标元素
                 X.set(i);//传指
                 Y.set(j);
                 return;
             }
         }
         boolean Move(int mod){
             myInt X=new myInt();
             myInt Y=new myInt();
             FindPos(0,X,Y);
             int x=X.get();
             int y=Y.get();//找到0的位置
         //    System.out.println("x="+x+"y="+y);
             switch(mod){
             case 0://上
                 if(y>0) swap(x,y,x,y-1);
                 else return false;
                 break;
             case 1://下
                 if(y<2) swap(x,y,x,y+1);
                 else return false;
                 break;
             case 2://左
                 if(x>0) swap(x,y,x-1,y);
                 else return false;
                 break;
             default://右
                 if(x<2) swap(x,y,x+1,y);
                 else return false;
                 break;
             }
             return true;
         }
         void swap(int x1,int y1,int x2,int y2){//(x1,y1)与(x2,y2)交换
             int tmp=data[x1][y1].get();                //tmp=x1
             data[x1][y1].set(data[x2][y2].get());    //x1=x2
             data[x2][y2].set(tmp);                    //x2=tmp
         }
         boolean FindTarget(int[][] obj){//找到目标
             int i,j;
             for(i=0;i<3;i++) for(j=0;j<3;j++) if(obj[i][j]!=data[i][j].get()) return false;//只要有一个不符,错误
             return true;
         }
         boolean equalWith(ints obj){//与目标相同
             int i,j;
             for(i=0;i<3;i++)
                 for(j=0;j<3;j++)
                     if(obj.data[i][j].get()!=data[i][j].get()) return false;//只要有一个不符,错误
             return true;
         }
     }
     List<ints> queue=new ArrayList<ints>();//设置队列
     EightNumProblem(){}
     boolean FindInQueue(ints elem){//查看队列中是否有该元素
         for(int i=0;i<queue.size();i++){
             if(elem.equalWith(queue.get(i))){
                 return true;
             }
         }
         return false;
     }
     void solve(){
         ints root=new ints(source);//用源数据构造根节点
         root.parent=-1;//父编号设置特殊值: -1
         int front=0;
         int rear=0;
         queue.add(root);//根节点入队
         rear++;
         int flag=0;
         while(front<rear && flag<100000){
             for(int j=0;j<4;j++){
                 flag++;
                 ints tmp=queue.get(front);        //出队
                 ints node=new ints(tmp);        //拷贝出新的结点
                 if(node.Move(j) && (!FindInQueue(node)) ){        //如果变换成功 并且这个结点在队列中是新的
                     node.parent=front;
                     if(node.FindTarget(target)){
                         System.out.println("找到");
                         PrintSource(node);
                         return;        //找到目标,跳出循环
                     }
                     queue.add(node);
                     rear++;                        //入队
                 }
             }
             front++;
         }
     }
     void PrintSource(ints obj){
         while(obj.parent!=-1){
             System.out.println(obj);
             obj=queue.get(obj.parent);
         }
     }
 }
BFS实现8数码问题,思考与总结的更多相关文章
- HDU 1043 Eight (BFS·八数码·康托展开)
		
题意 输出八数码问题从给定状态到12345678x的路径 用康托展开将排列相应为整数 即这个排列在全部排列中的字典序 然后就是基础的BFS了 #include <bits/stdc++.h ...
 - BFS:八数码问题
		
#include <iostream> #include <cstdlib> #include <cstdio> #include <cstring> ...
 - BFS(八数码) POJ 1077 || HDOJ 1043 Eight
		
题目传送门1 2 题意:从无序到有序移动的方案,即最后成1 2 3 4 5 6 7 8 0 分析:八数码经典问题.POJ是一次,HDOJ是多次.因为康托展开还不会,也写不了什么,HDOJ需要从最后的状 ...
 - UVALive 6665 Dragonâs Cruller --BFS,类八数码问题
		
题意大概就是八数码问题,只不过把空格的移动方式改变了:空格能够向前或向后移动一格或三格(循环的). 分析:其实跟八数码问题差不多,用康托展开记录状态,bfs即可. 代码: #include <i ...
 - [cdoj1380] Xiper的奇妙历险(3) (八数码问题 bfs + 预处理)
		
快要NOIP 2016 了,现在已经停课集训了.计划用10天来复习以前学习过的所有内容.首先就是搜索. 八数码是一道很经典的搜索题,普通的bfs就可求出.为了优化效率,我曾经用过康托展开来优化空间,甚 ...
 - 八数码问题+路径寻找问题+bfs(隐式图的判重操作)
		
Δ路径寻找问题可以归结为隐式图的遍历,它的任务是找到一条凑够初始状态到终止问题的最优路径, 而不是像回溯法那样找到一个符合某些要求的解. 八数码问题就是路径查找问题背景下的经典训练题目. 程序框架 p ...
 - 【算法】BFS+哈希解决八数码问题
		
15拼图已经有超过100年; 即使你不叫这个名字知道的话,你已经看到了.它被构造成具有15滑动砖,每一个从1到15上,并且所有包装成4乘4帧与一个瓦块丢失.让我们把丢失的瓷砖“X”; 拼图的目的是安排 ...
 - hdu-1043(八数码+bfs打表+康托展开)
		
参考文章:https://www.cnblogs.com/Inkblots/p/4846948.html 康托展开:https://blog.csdn.net/wbin233/article/deta ...
 - 【基础练习】【BFS+A*】codevs1225八数码难题题解
		
题目描写叙述 Description Yours和zero在研究A*启示式算法.拿到一道经典的A*问题,可是他们不会做,请你帮他们. 问题描写叙述 在3×3的棋盘上,摆有八个棋子,每一个棋子上标有1至 ...
 
随机推荐
- SQL  -----------        借助视图写多表查询
			
在多表查询中可能遇到两表.三表乃致四表查询,自己进行直接用sql 语句进行书写的话可能比较难,但是可以借助视图进行分析,书写 1.右击视图点击新建 选择需要的表点击添加,注意两个表之间要有相同的字段 ...
 - Task 小记
			
1. 注意 Task 执行的顺序. 如下代码: IQueryable<T> querySet; if (preConditionExpression == null) { querySet ...
 - CTS,CLS,CLR解释
			
问题阐述 CTS.CLS和 CLR分别是什么意思? 专家解答 CTS.CLS和 CLR是.NET框架的 3个核心部分,下面分别对它们进行介绍. (1)CTS CTS即通用类型系统,它定义了如何在.NE ...
 - mini Redis(项目 二)
			
一个仿Redis的内存数据库(主要用来做命令解析)服务端, 客户端使用的开源工具 : https://dom4j.github.io/ github:https://github.com/h ...
 - Python关于多继承
			
大部分面向对象的编程语言(除了C++)都只支持单继承,而不支持多继承,为什么呢?因为多继承不仅增加编程复杂度,而且容易导致莫名其妙的错误. Python虽然语法上支持多继承,但是却不推荐使用多继承,而 ...
 - 【selenium】基于python语言,如何用select选择下拉框
			
在项目测试中遇到了下拉框选择的控件,来总结下如何使用select选择下拉框: 下图是Select类的初始化描述,意思是,给定元素是得是select类型,不是就抛异常.接下来给了例子:要操作这个sele ...
 - 【转】fastjson-1.2.47-RCE
			
Fastjson <= 1.2.47 远程命令执行漏洞利用工具及方法,以及避开坑点 以下操作均在Ubuntu 18下亲测可用,openjdk需要切换到8,且使用8的javac > java ...
 - VMware + CentOS 7搭建环境(二)
			
1.环境要求建议使用VMwareWorkstation虚拟机软件:可以使用快照功能,保存虚拟机状态:本文档示例版本10.0.1:1.2 CentOS系统的iso文件; 下载好的.iso的压缩文件格式, ...
 - Python基础-numpy
			
创建数组 numpy.array():括号内可以是列表.元祖.数组.生成器等 numpy.arange():类似range(),在给定间隔内返回均匀间隔的值 #numpy.linspace() 返回在 ...
 - Django框架(九)-- 多表操作:一对一、一对多、多对多的增删改,基于对象/双下划线的跨表查询、聚合查询、分组查询、F查询与Q查询
			
一.创建多表模型 一对一:OneToOneField 一对多:ForeignKey 多对多:ManyToManyField 创建表时,会自动添加一个nid字段,并且自增,所以id可以不用手动创建 On ...