帮同学写的八数码,启发式搜索

创建两个表open,close,分别用的stl中的优先队列priority_queue和map,好久没写过代码了,bug调了半天

 #include <iostream>
#include <cstdio>
#include <cstring>
#include <set>
#include <queue>
#include <algorithm>
#include <vector>
#include <map>
#include <time.h>
using namespace std;
struct Item //每一个状态
{
int state[][];
int Pre; //父状态在path中的下标
int F,G,H; //估计函数 F=G+H
Item(int state[][],int Pre,int G,int H) //构造函数
{
this->Pre=Pre;
this->G=G;
this->H=H;
this->F=G+H;
for(int i=;i<;i++)
for(int j=;j<;j++)
this->state[i][j]=state[i][j];
}
bool operator <(const Item temp) const //运算符重载,用于priority_queue中元素的比较
{
return F>temp.F;
}
bool operator ==(const Item temp) const
{
for(int i=;i<;i++)
for(int j=;j<;j++)
if(state[i][j]!=temp.state[i][j]) return ;
return ;
}
}; priority_queue<Item> Open; //存储扩展出但还没有访问的表
map<int,bool> Close; //存储已经访问过的节点
vector<Item> path; //保存路径
int arrays[][]={,,,,,,,,},arraye[][]={,,,,,,,,}; //八数码初始状态和目标状态
int dx[]={,,-,},dy[]={,-,,}; //四个方向扩展
int CalcuH(const int a0[][],const int a1[][]) //CalcuH(当前状态,目标状态)计算 H,如果目标状态和当前状态某个位置数字不同,dis自加1
{
int dis=;
for(int i=;i<;i++)
for(int j=;j<;j++)
if(a0[i][j]!=a1[i][j]) dis++;
return dis;
}
bool Judge(const int p0[][],const int p1[][]) //两者逆序数奇偶性相等,看八数码是否有解
{
int ss = , ee = ;
for(int i=; i<; ++i)
for(int j=; j<i; ++j) {
if(p0[j/][j%] != && p0[j/][j%] < p0[i/][i%]) ++ss;
if(p1[j/][j%] != && p1[j/][j%] < p1[i/][i%]) ++ee;
}
return (ss&) == (ee&);
}
int GetIndex(const int a[][]) //获取hash值,将Close[t]设置为1,表示已经访问过
{
int t=;
for(int i=;i<;i++)
for(int j=;j<;j++)
t=t*+a[i][j];
return t;
}
int PrintPath(const Item p) //递归打印路径
{
if(p.Pre==-)
{
for(int i=;i<;i++)
{
for(int j=;j<;j++)
cout<<" "<<p.state[i][j]<<" ";
cout<<endl;
}
cout<<endl;
return ;
}
PrintPath(path[p.Pre]);
cout<<p.G<<" ==>"<<endl;
for(int i=;i<;i++)
{
for(int j=;j<;j++)
cout<<" "<<p.state[i][j]<<" ";
cout<<endl;
}
cout<<endl;
return ;
}
/*search()函数中的思路:
1.将初始节点放入open。(open是优先队列,f最小的节点排在队列的最前面)
2.从open中取出f最小的节点p,放入到path中,如果为目标节点,则递归打印路径。否则将该状态放入到close中,并生成他的扩展节点集P(就是将空白点往四个方向移动)。
3.对于扩展出的每个子节点 temp:
temp.calcuf(),计算f,pre,
如果temp不在close,就把它放入open中,否则不管
4.回到步骤2; 八数码无解情况判断:
初始状态和目标状态的逆序数奇偶性相同,则可到达
*/
void Search(Item s,int end[][])
{
int x,y,mx,my;
path.clear();
Open.push(s);
while()
{
Item e=Open.top();
Open.pop();
path.push_back(e);
int in=GetIndex(e.state);
Close[in]=; //标记表示已经访问过
int len=path.end()-path.begin()-; //获取e节点在path中的位置,他是扩展出的节点的父节点。
if(CalcuH(e.state,end)==)
{
//cout<<e.G<<endl;
cout<<"一共需要"<<e.G<<"步"<<endl;
PrintPath(e);
return;
}
for(int i=;i<;i++) //找到0的位置,0表示空白
for(int j=;j<;j++)
if(e.state[i][j]==)
x=i,y=j;
for(int i=;i<;i++) //向四个方向扩展
{
mx=x+dx[i],my=y+dy[i];
if(mx>||mx<||my<||my>) //判断是否跑出3*3的数组
continue;
swap(e.state[mx][my],e.state[x][y]); //将空白点与周围点交换位置
Item temp(e.state,len,e.G+,CalcuH(e.state,arraye)); //构造出新的状态节点
swap(e.state[mx][my],e.state[x][y]); //再交换回来
int index=GetIndex(temp.state); //获取hash值
if(!Close.count(index))
{
Open.push(temp);
}
}
}
return;
}
int main()
{
clock_t t=clock(),e;
Item s(arrays,-,,CalcuH(arrays,arraye));
if(Judge(arrays,arraye)) //判断是否有解
Search(s,arraye);
else
cout<<"no path"<<endl;
e=clock();
cout<<"run time : "<<e-t<<" ms"<<endl;
return ;
}

A*八数码的更多相关文章

  1. A*算法 -- 八数码问题和传教士过河问题的代码实现

    前段时间人工智能的课介绍到A*算法,于是便去了解了一下,然后试着用这个算法去解决经典的八数码问题,一开始写用了挺久时间的,后来试着把算法的框架抽离出来,编写成一个通用的算法模板,这样子如果以后需要用到 ...

  2. 八数码问题:C++广度搜索实现

    毕竟新手上路23333,有谬误还请指正. 课程设计遇到八数码问题(这也是一坨),也查过一些资料并不喜欢用类函数写感觉这样规模小些的问题没有必要,一开始用深度搜索却发现深搜会陷入无底洞,如果设定了深度限 ...

  3. ACM/ICPC 之 BFS-广搜进阶-八数码(经典)(POJ1077+HDU1043)

    八数码问题也称为九宫问题.(本想查查历史,结果发现居然没有词条= =,所谓的历史也就不了了之了) 在3×3的棋盘,摆有八个棋子,每个棋子上标有1至8的某一数字,不同棋子上标的数字不相同.棋盘上还有一个 ...

  4. BFS(八数码) POJ 1077 || HDOJ 1043 Eight

    题目传送门1 2 题意:从无序到有序移动的方案,即最后成1 2 3 4 5 6 7 8 0 分析:八数码经典问题.POJ是一次,HDOJ是多次.因为康托展开还不会,也写不了什么,HDOJ需要从最后的状 ...

  5. 双向广搜+hash+康托展开 codevs 1225 八数码难题

    codevs 1225 八数码难题  时间限制: 1 s  空间限制: 128000 KB  题目等级 : 钻石 Diamond   题目描述 Description Yours和zero在研究A*启 ...

  6. UVALive 6665 Dragon’s Cruller --BFS,类八数码问题

    题意大概就是八数码问题,只不过把空格的移动方式改变了:空格能够向前或向后移动一格或三格(循环的). 分析:其实跟八数码问题差不多,用康托展开记录状态,bfs即可. 代码: #include <i ...

  7. P1379 八数码问题

    aoapc上的八数码问题,在luogu上也有类似的题,p1379,经典题目,lrj给出了一个算法,同时给出了三种判重的方法.本来想用std::queue改写一下,但是出了各种问题,只好抄代码ac掉这道 ...

  8. [cdoj1380] Xiper的奇妙历险(3) (八数码问题 bfs + 预处理)

    快要NOIP 2016 了,现在已经停课集训了.计划用10天来复习以前学习过的所有内容.首先就是搜索. 八数码是一道很经典的搜索题,普通的bfs就可求出.为了优化效率,我曾经用过康托展开来优化空间,甚 ...

  9. hdu 1043 Eight 经典八数码问题

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1043 The 15-puzzle has been around for over 100 years ...

  10. A*算法解决八数码问题 Java语言实现

    0X00 定义 首先要明确一下什么是A*算法和八数码问题? A*(A-Star)算法是一种静态路网中求解最短路径最有效的直接搜索方法也是一种启发性的算法,也是解决许多搜索问题的有效算法.算法中的距离估 ...

随机推荐

  1. Eric Pement的单行awk命令收集

    超实用的. awk1line_zh-CN.txt 可惜中文版的网址好像不能访问了.. HANDY ONE-LINE SCRIPTS FOR AWK 30 April 2008 Compiled by ...

  2. 在VC中检测内存泄漏

    声明:checkleaks.h和checkleaks.cpp这两个文件中的代码是在网上COPY的,但原来那个网站现在却找不到了 所以,这篇文章不算完全原创,呵呵. 就当作是一个存档吧 先上代码: // ...

  3. Another Look at Events(再谈Events)

    转载:http://www.qtcn.org/bbs/simple/?t31383.html Another Look at Events(再谈Events) 最近在学习Qt事件处理的时候发现一篇很不 ...

  4. c#—— Task.FromResult 的使用

    Task.FromResult用来创建一个带返回值的.已完成的Task. 场景一:以同步的方式实现一个异步接口方法 比如有一个接口包含异步方法. interface IMyInterface { Ta ...

  5. Web前端开发

    由于互联网的各种兴起,网页开发似乎也火了,催生了github上各种js的轮子,各种重复,各种框架和库,什么Jquery,bootstrap等等.面对这么多框架和库我们在工程上该如何取舍(trade-o ...

  6. QComboBox调用clear函数崩溃的问题

    项目有个需求是这样的: QComboBox需要动态清楚添加Item列表,并且之前设置了QComboBox当前index改变的信号,一旦这个clear调用,当前index就改变,因为一旦改变,信号就发出 ...

  7. ruby文档

    http://www.ruby-doc.org/http://rubyonrails.org/https://www.ruby-lang.org/zh_cn/downloads/http://ruby ...

  8. chrome浏览器测试js函数

    1.直接在console中写入代码 2.既要写函数,又要写执行函数的代码. 不关闭网页,函数能够在内存中存活很久 浏览器都能记住函数. 当然,在其他页面无效.

  9. HDOJ 1323 Perfection(简单题)

    Problem Description From the article Number Theory in the 1994 Microsoft Encarta: "If a, b, c a ...

  10. 如何在Windows服务程序中读写HKEY_CURRENT_USER注册表

    在服务程序中想要对注册表HKEY_CURRENT_USER下的内容进行读写,不会返回失败,但是始终无效.原因是: 1.服务运行在系统权限之下,而不是任何一个用户 2.HKEY_CURRENT_USER ...