背景

Yours和zero在研究A*启发式算法.拿到一道经典的A*问题,但是他们不会做,请你帮他们.

描述

在3×3的棋盘上,摆有八个棋子,每个棋子上标有1至8的某一数字。棋盘中留有一个空格,空格用0来表示。空格周围的棋子可以移到空格中。要求解的问题是:给出一种初始布局(初始状态)和目标布局(为了使题目简单,设目标状态为123804765),找到一种最少步骤的移动方法,实现从初始布局到目标布局的转变。

格式

输入格式

输入初试状态,一行九个数字,空格用0表示

输出格式

只有一行,该行只有一个数字,表示从初始状态到目标状态需要的最少移动次数(测试数据中无特殊无法到达目标状态数据)

样例1

样例输入1

283104765

样例输出1

4

  这题直接广搜是可以的,不过非常地耗费内存和时间,所以这里用到了A*算法

股价函数是以它和目标节点的差作股价,不过单用股价函数是不可以的(全W的教训)

还要有现在所走的步数,把两者相加,得到优先级,优先级越低的越先搜索

priority = h(x) + step;

  如何说明这个的正确性呢?假设有有一个节点x,h(x) = 2,如果它不能尽快地达到目标状态,以至于优先级超过排在第二的节点y,那么y就会被取出队列进行更新。要使股价函数h(x)的值要减少1(当h(x)=2时是特例),至少需要移动一步,这样就能够保证第一次搜到目标节点一定步数是最少的。如果还不明白,就这么再说一下个人的理解,(h[x]+step)是按照最优的情况移动一次h(x)就减少了1的步数加1进行预算,如果最优的情况下x都不比y优,那么就应当先搜索y。

Code:

 /**
* Vijos.org
* Problem#1360
* Accepted
* Time:76ms
* Memory:996k
**/
#include<iostream>
#include<queue>
#include<set>
using namespace std;
typedef bool boolean;
typedef class MyData{
public:
char datas[][];
void in(){
for(int i=;i<=;i++){
for(int j=;j<=;j++){
cin>>datas[i][j];
}
}
}
MyData(){}
MyData(string str){
for(int i=;i<=;i++){
this->datas[i/][i%] = str[i];
}
}
boolean equals(MyData another){
for(int i=;i<=;i++){
for(int j=;j<=;j++){
if(this->datas[i][j]!=another.datas[i][j]) return false;
}
}
return true;
}
boolean operator <(MyData another) const{ for(int i=;i<=;i++){
for(int j=;j<=;j++){
if(this->datas[i][j]!=another.datas[i][j]) return this->datas[i][j]<another.datas[i][j];
}
}
return false;
}
}MyData;
typedef class Node{
public:
int pro;
int step;
MyData d;
int x;
int y;
Node():pro(),step(){}
Node(int pro,int step,MyData d):pro(pro),step(step),d(d){}
boolean operator <(Node another) const{
return this->pro>another.pro;
}
}Node;
int fstep = -;
priority_queue<Node> que;
set<MyData> s;
int m[][]={{,,-,},{,,,-}};
MyData aim("");
int h(Node node){
int result = ;
for(int i=;i<=;i++){
for(int j=;j<=;j++){
if(node.d.datas[i][j]!=aim.datas[i][j]) result++;
}
}
return result;
}
void swap(Node* node,int x,int y,int x1,int y1){
char a=node->d.datas[x][y];
node->d.datas[x][y]=node->d.datas[x1][y1];
node->d.datas[x1][y1]=a;
}
void find(Node start){
start.step = ;
start.pro=h(start);
for(int a=;a<=;a++){
for(int b=;b<=;b++){
if(start.d.datas[a][b]==''){
start.x=a;
start.y=b;
break;
}
}
}
s.insert(start.d);
que.push(start);
while(!que.empty()){
Node e = que.top();
que.pop();
if(fstep != -&&e.step >= fstep) continue;
if(e.d.equals(aim)) fstep = e.step;
for(int i=;i<=;i++){
Node eu = e;
int x=eu.x,y=eu.y;
eu.x += m[][i];
eu.y += m[][i];
if(eu.x>=&&eu.x<=&&eu.y>=&&eu.y<=){
swap(&eu,x,y,eu.x,eu.y);
eu.pro = h(eu) + eu.step + ;
eu.step++;
if(!s.count(eu.d)){
s.insert(eu.d);
que.push(eu);
}
}
}
}
}
int main(){
MyData d;
d.in();
find(Node(,,d));
cout<<fstep;
return ;
}

vijos 1360 八数码问题 - 启发式搜索的更多相关文章

  1. Vijos 1360 - 八数码问题 - [A*]

    题目链接:https://vijos.org/p/1360 优先队列BFS: 这个八数码问题本身其实是之前人工智能实验课的作业…… 首先,如果不带估价函数,直接用优先队列BFS,肯定也是能得到正确结果 ...

  2. 【宽搜】Vijos P1360 八数码问题

    题目链接: https://vijos.org/p/1360 题目大意: 3x3格子上放1~8数字,一个空位,每次空位可与上下左右交换,固定终止布局,求输入的起始布局需要几步到达终止布局 题目思路: ...

  3. luoguP1379 八数码难题[启发式搜索]

    题目描述 在3×3的棋盘上,摆有八个棋子,每个棋子上标有1至8的某一数字.棋盘中留有一个空格,空格用0来表示.空格周围的棋子可以移到空格中.要求解的问题是:给出一种初始布局(初始状态)和目标布局(为了 ...

  4. c++ 启发式搜索解决八数码问题

    本文对八数码问题 启发式搜索 (C++)做了一点点修改 //fn=gn+hn #include<iostream> #include<queue> #include<st ...

  5. A*八数码

    帮同学写的八数码,启发式搜索 创建两个表open,close,分别用的stl中的优先队列priority_queue和map,好久没写过代码了,bug调了半天 #include <iostrea ...

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

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

  7. Codevs 1225 八数码难题

    1225 八数码难题 时间限制: 1 s 空间限制: 128000 KB 题目等级 : 钻石 Diamond 题目描述 Description Yours和zero在研究A*启发式算法.拿到一道经典的 ...

  8. 八数码问题 Eight Digital Problem

    八数码问题 利用启发式搜索,找出以下问题的最优解. #include <iostream> #include <vector> #include <algorithm&g ...

  9. 【洛谷P1379】八数码难题(广搜、A*)

    八数码难题 题目描述 一.广搜: 首先要考虑用什么存每一个状态 显然每个状态都用一个矩阵存是很麻烦的. 我们可以考虑将一个3*3的矩阵用一个字符串或long long 存. 每次扩展时再转化为矩阵. ...

随机推荐

  1. c# listView中列宽随列中的内容自动调整

    1.创建一个类 ListViewAutoChange  作用:自动调整ListView的列宽 代码如下:(内容很容易理解,没加注释) using System; using System.Collec ...

  2. Django实现微电影网站

    主要实现功能: 注册,登陆,播放视频,评论视频,xadmin实现后台提供视频管理,权限管理等等 首页(搜索,筛选) 搜索页面 播放页面 个人中心 后台 源码下载 环境配置:python2.7  pip ...

  3. range() 与 np.arange()

    转自:http://blog.csdn.net/lanchunhui/article/details/49493633 range()返回的是range object,而np.nrange()返回的是 ...

  4. 利用VS正则替换删除文本行首数据等字符

    删除以数字开头的加‘.’的行首序号 ^[0-9][0-9][.]

  5. Java-SpringMvc-响应Html代码展示

    代码 @RequestMapping(value = "/test.do", method = {RequestMethod.GET}) public void test(Http ...

  6. MongoDB复制集的工作原理介绍(二)

    复制集工作原理 1)数据复制原理 开启复制集后,主节点会在 local 库下生成一个集合叫 oplog.rs,这是一个有限集合,也就是大小是固定的.其中记录的是整个mongod实例一段时间内数据库的所 ...

  7. Kaggle案例泰坦尼克号问题

    泰坦里克号预测生还人口问题 泰坦尼克号问题背景 - 就是那个大家都熟悉的『Jack and Rose』的故事,豪华游艇倒了,大家都惊恐逃生,可是救生艇#### 的数量有限,无法人人都有,副船长发话了l ...

  8. Windows程序自启动方法汇总

    文件夹 一.当前用户专有的启动文件夹 二.对所有用户有效的启动文件夹 三.Load注册键 四.Userinit注册键 五.Explorer\Run注册键 六.RunServicesOnce注册键 七. ...

  9. 下载YouTube视频的方法

    这个网站就可以: http://www.clipconverter.cc/ 更多的网站及介绍参考知乎:http://www.zhihu.com/question/19964181

  10. Git—使用方法

    1.:插件的安装(eclipse LUNA版本之后已经自动集成,不需要安装插件). * 先打开该网页提供了对应版本的EGit,自己选择相应的版本.(http://wiki.eclipse.org/EG ...