题目链接:http://poj.org/problem?id=1077

思路分析:题目要求在找出最短的移动路径,使得从给定的状态到达最终状态。

<1>搜索算法选择:由于需要找出最短的移动路径,所以选择bfs搜索

<2>判重方法:

将空格视为数字9,则可以将状态的集合视为1-9的排列组合的集合,根据康托展开,将每一个状态映射到一个正整数中;

在由哈希表进行判重。

<3>状态压缩:在搜索时使用将每个状态转换为一个由1-9组成的9位数字即可进行状态压缩与解压。

<4>双向广度优先搜索的技巧:

1)优点:对于给定了初始状态与目标状态的问题,可以使用双向搜索进行搜索,更能节省空间与时间。

2)双向广度优先搜索的思想:双向广度优先搜索同时开始两种搜索;一个广度优先搜索从给定的状态向目标状态搜索,另外一个广度优先搜索从目标状态

向给定的状态搜索,则会生成两个状态树;搜索时记录每个状态树中的父节点与子节点的关系;当从每个状态树中的一个根结点开始扩展节点时,若扩展

的结点在该状态树中已经出现,则不扩展该节点,若扩展的结点在另一棵状态树中已经存在,则就找到了一条路径连接了初始状态与目标状态(是否最短?),

因为在一个状态树中初始状态与该状态之间与存在一条路径,而在另一棵状态树中,该状态与目标状态之间存在一条路径,所以以该扩展的结点为连接点,

连接了两棵状态树中的初始状态与目标状态;

代码如下:

#include <iostream>
#include <cstring>
#include <cmath>
using namespace std; const int MAX_N = + ; // 10! + 10
int set[MAX_N]; // 状态集合,用来判重,并记录状态的被搜索情况(0:未被搜索 1:正向搜索 2:反向搜索)
int map[]; // 记录图的状态
char path[MAX_N]; // 在打印路径是记录路径
const int FACT[] = {, , , , , , , , };
const int MOVE[][] = {{, -}, {, }, {-, }, {, }}; struct Node
{
int state_num;
int pre, next; // 状态树记录子节点与父节点
char pre_dir, next_dir; // 记录父节点扩展到子节点的移动方向
}state_queue[MAX_N]; int Canto()
{
int state_num = ;
for (int i = ; i < ; ++i)
{
int temp = map[i] - ; for (int j = ; j < i; ++j)
temp -= (map[j] < map[i]);
state_num += temp * FACT[ - i];
}
return state_num;
} void StateNumToMAP(int num)
{
int i = ;
while (num)
{
map[i--] = num % ;
num /= ;
}
} char MoveDirection(bool forward, int i)
{
char result = ; if (!forward)
{
if ( <= i && i <= )
i = - i;
else
i = - i;
} switch (i)
{
case : result = 'u'; break;
case : result = 'd'; break;
case : result = 'l'; break;
case : result = 'r'; break;
}
return result;
} int MapToStateNum()
{
int ans = ; for (int i = ; i < ; ++i)
ans = ans * + map[i];
return ans;
} int BFS()
{
int head, tail, state_canto_val;
Node start, end; head = tail = ;
start.state_num = MapToStateNum();
start.pre = -; // -1,表示无父节点
start.pre_dir = -; // 同上
start.next = ; // 0表示为根结点
start.next_dir = ; // 同上
state_canto_val = Canto();
set[state_canto_val] = ; if (start.state_num == )
return -; end.state_num = ;
end.next = -; // -1表示无父节点
end.next_dir = -; // 同上
end.pre = ; // 0表示为根节点
end.pre_dir = ; // 同上 state_queue[tail++] = start;
state_queue[tail++] = end;
set[] = -; while (head < tail)
{
int now_x, now_y, next_x, next_y;
Node now_state; now_state = state_queue[head];
StateNumToMAP(now_state.state_num);
state_canto_val = Canto(); for (int i = ; i < ; ++i)
{
if (map[i] == )
{
now_x = i % , now_y = i / ;
break;
}
}
for (int i = ; i < ; ++i)
{
int temp_swap;
Node next_state; next_x = now_x;
next_y = now_y;
next_x += MOVE[i][];
next_y += MOVE[i][]; if (next_x < || next_x >=
|| next_y < || next_y >= )
continue;
temp_swap = map[now_x + now_y * ];
map[now_x + now_y * ] = map[next_x + next_y * ];
map[next_x + next_y * ] = temp_swap; state_canto_val = Canto();
if (state_queue[head].pre == && set[state_canto_val] == )
{
set[state_canto_val] = -tail;
next_state.state_num = MapToStateNum();
next_state.pre = ;
next_state.pre_dir = ;
next_state.next = head;
next_state.next_dir = MoveDirection(false, i);
state_queue[tail++] = next_state;
}
else if (state_queue[head].pre == && set[state_canto_val] > )
{
state_queue[abs(set[state_canto_val])].next = head;
state_queue[abs(set[state_canto_val])].next_dir = MoveDirection(false, i);
return abs(set[state_canto_val]);
}
else if (state_queue[head].next == && set[state_canto_val] == )
{
set[state_canto_val] = tail;
next_state.state_num = MapToStateNum();
next_state.pre = head;
next_state.pre_dir = MoveDirection(true, i);
next_state.next = ;
next_state.next_dir = ;
state_queue[tail++] = next_state;
}
else if (state_queue[head].next == && set[state_canto_val] < )
{
state_queue[abs(set[state_canto_val])].pre = head;
state_queue[abs(set[state_canto_val])].pre_dir = MoveDirection(true, i);
return abs(set[state_canto_val]);
} temp_swap = map[now_x + now_y * ];
map[now_x + now_y * ] = map[next_x + next_y * ];
map[next_x + next_y * ] = temp_swap;
}
head++;
}
return -;
} void PrintPath(int id)
{
int pos = ;
int temp_id = id; while (state_queue[temp_id].pre != -)
{
path[pos++] = state_queue[temp_id].pre_dir;
temp_id = state_queue[temp_id].pre;
} for (int i = pos - ; i >= ; --i)
printf("%c", path[i]); temp_id = id;
while (state_queue[temp_id].next != -)
{
printf("%c", state_queue[temp_id].next_dir);
temp_id = state_queue[temp_id].next;
} printf("\n");
} int main()
{
int ans = ;
char temp_value; for (int i = ; i < ; ++i)
{
cin >> temp_value;
if (temp_value == 'x')
map[i] = ;
else
map[i] = temp_value - '';
} memset(set, , sizeof(set));
ans = BFS();
if (ans == -)
printf("unsolvabel\n");
else if (ans == -)
printf("\n");
else
PrintPath(ans); return ;
}

poj 1077 Eight(双向bfs)的更多相关文章

  1. [poj] 2549 Sumsets || 双向bfs

    原题 在集合里找到a+b+c=d的最大的d. 显然枚举a,b,c不行,所以将式子移项为a+b=d-c,然后双向bfs,meet int the middle. #include<cstdio&g ...

  2. POJ 1077 Eight (BFS+康托展开)详解

    本题知识点和基本代码来自<算法竞赛 入门到进阶>(作者:罗勇军 郭卫斌) 如有问题欢迎巨巨们提出 题意:八数码问题是在一个3*3的棋盘上放置编号为1~8的方块,其中有一块为控制,与空格相邻 ...

  3. Eight (HDU - 1043|POJ - 1077)(A* | 双向bfs+康拓展开)

    The 15-puzzle has been around for over 100 years; even if you don't know it by that name, you've see ...

  4. HDU 1043 & POJ 1077 Eight(康托展开+BFS+预处理)

    Eight Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 30176   Accepted: 13119   Special ...

  5. HDU 1043 & POJ 1077 Eight(康托展开+BFS | IDA*)

    Eight Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 30176   Accepted: 13119   Special ...

  6. POJ 3170 Knights of Ni (暴力,双向BFS)

    题意:一个人要从2先走到4再走到3,计算最少路径. 析:其实这个题很水的,就是要注意,在没有到4之前是不能经过3的,一点要注意.其他的就比较简单了,就是一个双向BFS,先从2搜到4,再从3到搜到4, ...

  7. POJ 3126 Prime Path 解题报告(BFS & 双向BFS)

    题目大意:给定一个4位素数,一个目标4位素数.每次变换一位,保证变换后依然是素数,求变换到目标素数的最小步数. 解题报告:直接用最短路. 枚举1000-10000所有素数,如果素数A交换一位可以得到素 ...

  8. POJ 1915-Knight Moves (单向BFS &amp;&amp; 双向BFS 比)

    主题链接:Knight Moves 题意:8个方向的 马跳式走法 ,已知起点 和终点,求最短路 研究了一下双向BFS,不是非常难,和普通的BFS一样.双向BFS只是是从 起点和终点同一时候開始搜索,可 ...

  9. POJ——3126Prime Path(双向BFS+素数筛打表)

    Prime Path Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 16272   Accepted: 9195 Descr ...

随机推荐

  1. URL编码解码

    ios url 编码和解码 1.url编码 ios中http请求遇到汉字的时候或者像是%…@#¥%&*这些字符的时候也可以使用下面的方法,需要转化成UTF-8,用到的方法是: NSString ...

  2. MongoDB入门学习(一)—— 安装和启动

    最近由于工作需要,开始学习MongoDB数据库了.第一篇博文就从这里开始吧,以此记录下学习中的点点滴滴,为自己加油呢! (一) MongoDB简介 网上搜搜了一下:(来源:http://www.run ...

  3. Java多线程yield

    前言: 前几天复习了一下多线程,发现有许多网上讲的都很抽象,所以,自己把网上的一些案例总结了一下! 一. Thread.yield( )方法: 使当前线程从执行状态(运行状态)变为可执行态(就绪状态) ...

  4. Apache与Nginx优缺点比较

    本文来源:收集.整理自互联网 1.nginx相对于apache的优点:  轻量级,同样起web 服务,比apache 占用更少的内存及资源  抗并发,nginx 处理请求是异步非阻塞的,而apache ...

  5. javascript小练习—点击将DIV变成红色(通过for循环遍历)

    <!DOCTYPE html> <html> <head lang="en"> <meta charset="UTF-8&quo ...

  6. 推荐一款手机端的图片滑动插件iSlider

    首先先放出中文官方地址   http://be-fe.github.io/iSlider/index.html 这是demo 众所周知,移动端的图片滑动插件有很多,为什么我要推荐这个iSlider呢? ...

  7. jar文件につぃて

    打包jar文件和设置class路径: 查看jar文件内容:

  8. Java文本编辑器中遇到的问题详解

    今天介绍文件的读取和写入,分别用FileReader,FileWriter 1,FileWriter类(字符输出流类) 构造方法:FileWriter fw = new FileWriter(Stri ...

  9. Java I/O theory in system level

    参考文章: JAVA NIO之浅谈内存映射文件原理与DirectMemory Java NIO 2.0 : Memory-Mapped Files | MappedByteBuffer Tutoria ...

  10. HttpWebRequest使用注意(发生阻塞的解决办法)

    原文 http://www.cnblogs.com/Fooo/archive/2008/10/31/1323400.html HttpWebRequest使用注意(发生阻塞的解决办法) , count ...