Δ路径寻找问题可以归结为隐式图的遍历,它的任务是找到一条凑够初始状态到终止问题的最优路径,

而不是像回溯法那样找到一个符合某些要求的解。

八数码问题就是路径查找问题背景下的经典训练题目。

程序框架

  • process()  初始化vis数组,初始化初始节点到目标节点的移动距离
  • dfs()搜索到每一个节点,如果不是目标节点,对其依次扩展所有子节点,并判重,全部子节点搜索完全后,改变父节点;如果是目标节点成功返回
  • 输出最少移动步数

input:

2 6 4 1 3 7 0 5 8

8 1 5 7 3 6 4 0 2

ouput:

31

#include <stdio.h>
#include <stdlib.h>
#include <string.h> #define MAXSIZE 1000000 typedef int State[9];//s的素具类型是长度为100的数组,数组元素s[i]的数据类型是State是长度为10的数组,等同于定义了一个二维数组s[100]=iArr[100][9],数组元素师int
//int iarr[100][10],arr的数据类型是长度为100的数组,数组元素师arr[i],arr[i]的数据类型是长度为10的数组,数组元素师int
State st[MAXSIZE];//状态数一定要多定义,否则一不小心就超了
State stEnd;
int iDist[MAXSIZE]; int go[][2] =
{
{-1,0},
{1,0},
{0,-1},
{0,1}
}; int iVis[362880],fact[9];//9!=362880,8!=40320,9*8!=9!共有这么多排序,然后我们寻找,我们初始化fact
void init()
{
fact[0] = 1;
for(int i = 1 ; i < 9; i++)
{
fact[i] = fact[i-1]*i;
}
} //bool isInsert(State state)
bool isInsert(int n)//去重,采用编码与解码机制,确保一个9维状态只能映射到一个数字,并且映射的数字最大值不能超过9!
{
int iCode = 0;//编码值
for(int i = 0 ; i < 9 ; i++)
{
int iCnt = 0;
for(int j = i+1; j < 9;j++)
{
if(st[n][j] < st[n][i])//统计每个排列中,后面小于前面排列的数字个数
{
iCnt++;
}
}
iCode += fact[8-i]*iCnt;
}
if(iVis[iCode])//如果已经访问过
{
return false;
}
else
{
iVis[iCode] = 1;
return true;//同时完成赋值和返回值操作
}
} int bfs()
{
int iRear = 2,iFront = 1;
init();//这里进行判重,对于树不需要判断重复。但是对于图需要判断
while(iFront < iRear)
{
State& state = st[iFront];
if(memcmp(stEnd,state,sizeof(state)) == 0)//判断是否找到的工作要放在开头
{
return iFront;
} int iZ,iX,iY;
for(int i = 0 ; i < 9; i++)//确定0所在的位置
{
if(!state[i])
{
iZ = i;
iX = iZ / 3;
iY = iZ % 3;
break;//凡是寻找类的问题,一旦找到,必须用break跳出
}
}
//生成下一步位置
int iNewZ,iNewX,iNewY;
for(int i = 0; i < 4; i++)
{
iNewX = go[i][0] + iX;
iNewY = go[i][1] + iY;
iNewZ = iNewX*3 + iNewY;//确定0的新位置
if(iNewX >= 0 && iNewX < 3 && iNewY >= 0 && iNewY < 3)//剪枝
{
State& newState = st[iRear];//这里应该从队尾提前将原来老的状态拷贝给新的状态,再将新状态中需要修改0元素的地方进行修改,需要用引用,为修改做准备
memcpy(&newState,&state,sizeof(state));
newState[iNewZ] = state[iZ];//新矩阵0元素的位置上放0元素
newState[iZ] = state[iNewZ];//新矩阵原来放0元素的位置上现在放上新生成的0元素的坐标,这里必须用原来被交换元素的值替换
iDist[iRear] = iDist[iFront] + 1;//更新移动的步数
}
if(isInsert(iRear))//修改队尾指针
{
iRear++;
}
}
iFront++;//不管是否成功,修改队头
}
return -1;
} void process()
{
//初始化队头和队尾元素
for(int i = 0 ; i < 9;i++)
{
scanf("%d",&st[1][i]);
}
for(int j = 0 ; j < 9; j++)
{
scanf("%d",&stEnd[j]);
}
iDist[1] = 0;//设置第一步移动的距离为0
memset(iVis,0,sizeof(iVis));//初始化访问内存块,就是这句话没加导致错误的
} int main(int argc,char* argv[])
{
process();
int iRes = bfs();//返回的是front的值,但不是移动次数,移动次数得用dist来计算,因为这里是宽度优先搜索,如果用front的值,那么中间尝试的节点也算了
if(iRes > 0)
{
printf("%d\n",iDist[iRes]);
}
else
{
printf("-1\n");
}
system("pause");
return 0;
}

  

八数码问题+路径寻找问题+bfs(隐式图的判重操作)的更多相关文章

  1. hdoj 1495 非常可乐【bfs隐式图】

    非常可乐 Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Submis ...

  2. nyoj 21--三个水杯(隐式图bfs)

    三个水杯 时间限制:1000 ms  |  内存限制:65535 KB 难度:4 描述 给出三个水杯,大小不一,并且只有最大的水杯的水是装满的,其余两个为空杯子.三个水杯之间相互倒水,并且水杯没有标识 ...

  3. 【UVA】658 - It&#39;s not a Bug, it&#39;s a Feature!(隐式图 + 位运算)

    这题直接隐式图 + 位运算暴力搜出来的,2.5s险过,不是正法,做完这题做的最大收获就是学会了一些位运算的处理方式. 1.将s中二进制第k位变成0的处理方式: s = s & (~(1 < ...

  4. uva658(最短路径+隐式图+状态压缩)

    题目连接(vj):https://vjudge.net/problem/UVA-658 题意:补丁在修正 bug 时,有时也会引入新的 bug.假定有 n(n≤20)个潜在 bug 和 m(m≤100 ...

  5. UVA 658 状态压缩+隐式图+优先队列dijstla

    不可多得的好题目啊,我看了别人题解才做出来的,这种题目一看就会做的实在是大神啊,而且我看别人博客都看了好久才明白...还是对状态压缩不是很熟练,理解几个位运算用了好久时间.有些题目自己看着别人的题解做 ...

  6. HDU 1043 Eight 【经典八数码输出路径/BFS/A*/康托展开】

    本题有写法好几个写法,但主要思路是BFS: No.1 采用双向宽搜,分别从起始态和结束态进行宽搜,暴力判重.如果只进行单向会超时. No.2 采用hash进行判重,宽搜采用单向就可以AC. No.3 ...

  7. 由八数码问题引入。对BFS有更深考虑

    12号到今天共研究八数码问题poj1077,首先用的是普通BFS,遇到很多问题,开始用一个二级指针作为结构成员,知道了二级指针与二维数值名的不同!http://write.blog.csdn.net/ ...

  8. 基础学习总结(八)--Intent中显示意图和隐式意图的用法

    Intent(意图)主要是解决Android应用的各项组件之间的通讯.Intent负责对应用中一次操作的动作.动作涉及数据.附加数据进行描述,Android则根据此Intent的描述,负责找到对应的组 ...

  9. UVa 10603 Fill (BFS && 经典模拟倒水 && 隐式图)

    题意 : 有装满水的6升的杯子.空的3升杯子和1升杯子,3个杯子中都没有刻度.不使用道具情况下,是否可量出4升水呢? 你的任务是解决一般性的问题:设3个杯子的容量分别为a, b, c,最初只有第3个杯 ...

随机推荐

  1. webpack2教程--从入门到放弃

    开车之前,先介绍一些npm的命令: :D 进入D盘 mkdir webapp 创建webapp文件夹 cd webapp 进入webapp文件夹 mkdir webapp && cd ...

  2. 学习mysql语法--基础篇(二)

      前  言  mysql  mysql语法--本篇学习都是通过使用Navicat Premium(数据库管理工具),连接mysql数据. 本篇学习主要有两个部分: [SQL语句的组成]   DML ...

  3. html模板中的数字保留两位小数

    <script> //html模板中的数字保留两位小数 function formatCurrency(num) { num = num.toString().replace(/\$|\, ...

  4. Lamp单独安装(windows下)

    安装的软件清单:apache_2.2.9-win32-x86-openssl-0.9.8h-r2.msimysql-5.1.28-rc-win32.zipphp-5.2.6-Win32.zipphpM ...

  5. iOS10 相关的隐私设置,

    最近下载了几个demo,总是一运行就崩,看了下崩溃日志,有几个是因为没在plist里设置因此权限,而现在iOS 10 开始对隐私权限更加严格, 如需使用隐私权限需要在工程的info.plist文件中声 ...

  6. 解决发http get请求的时候不成功,出现android.os.NetworkOnMainThreadException的异常

    问题描述:在接游戏sdk的时候,由于游戏要求购买的时候是在主线程里面进行的,但是发http请求是不能在主线程里面发,否则就会出现android.os.NetworkOnMainThreadExcept ...

  7. 12.exception对象

    excepton对象是一个异常对象,当一个页面在运行过程中发生了异常,就产生了这个对象,如果一个jsp页面要应用此对象,就必须把isErrorPage设置为true,否则无法编译.它实际上是java. ...

  8. Spring Security -SpEL表达式

    Spring Security -SpEL表达式 开启SpEL表达式 <!-- use-expressions是否开启 SpEL表达式 o.s.s.web.access.expression.W ...

  9. accp8.0转换教材第11章JAjax加护扩展理解与练习

    ①杂记:前面有原生态JavaScript实现ajax这里又多了更简单的方法实现ajax ②$.get()方法的常用参数 参数 类型 说明 url String 必选,规定发送地址 data Plain ...

  10. APP测试点归纳

    1.2测试周期 测试周期可按项目的开发周期来确定测试时间,一般测试时间为两三周(即 15个工作日), 根据项目情况以及版本质量可适当缩短或延长测试时间.正式测试前先向主管确认项目排期. 1.3测试资源 ...