背景

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. sublime安装install package

    通过 https://sublime.wbond.net/Package%20Control.sublime-package 下载packageControl文件 下载完成后,打开sublime te ...

  2. 分布式网格缓存Coherence简介

    Coherence企业级缓存(一) 特点 摘要:Oracle Coherence是一个企业级的分布式集群缓存框架.具有自管理,自恢复,高可用性,高扩展性等优良特点,在电信BOSS等项目中有很大的应用价 ...

  3. XMind思维导图主题操作要点

  4. 008-jdk1.7版本新特性

    一.JDK1.7 名称:Dolphin(海豚) 发布日期:2011-07-28 新特性: 1.1.switch-case中可以使用字串 区分大小写.Java编译器通过switch使用String对象的 ...

  5. zkSNARK 零知识验证

    参考文献 ZCash7篇,有社区翻译版,但还是推荐看原汁原味的     https://z.cash/blog/snark-explain.html Vitalik3篇,小天才作者我就不介绍了,这三篇 ...

  6. 使用navicat mysql 远程连接数据库

    远程连接数据库,假设两台主机上都有navicat 客户端 远程主机A    ip地址:192.168.100.91  ,port  3306,数据库用户名 rootA   密码 123456A 本地主 ...

  7. 5分钟实现集群-NTP时间同步

    环境:VMware-Workstation-12-Pro,Windows-10,CentOS-7.5,Xshell5 NTP基本介绍 NTP(Network TimeProtocol,网络时间协议), ...

  8. Py-apply用法学习【转载】

    转自:https://blog.csdn.net/anshuai_aw1/article/details/82347016 1.Apply Python中apply函数的格式为:apply(func, ...

  9. 梯度下降法实现-python[转载]

    转自:https://www.jianshu.com/p/c7e642877b0e 梯度下降法,思想及代码解读. import numpy as np # Size of the points dat ...

  10. [LeetCode] 429. N-ary Tree Level Order Traversal_ Easy

    Given an n-ary tree, return the level order traversal of its nodes' values. (ie, from left to right, ...