题目链接: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. win7(32 bit) + IE8 环境,IE8无法弹窗(错误提示:“此网页上的错误可能会使它无法正确运行”),有关的系统注册信息损坏——解决方法

    错误截图如下:   IE有关的系统注册信息损坏,导致IE无法正常弹窗.   解决办法:重新注册与IE有关的DLL文件,具体如下: 1.以管理员身份运行附件脚本(新建txt文件,将下面代码复制到txt文 ...

  2. C++_基础_C与C++的区别2

    内容: (1)C++中的函数 (2)动态内存 (3)引用 (4)类型转换 (5)C++社区对C程序员的建议 1.C++中的函数1.1 函数的重载(1)重载的概念 在同一个作用域中,函数名相同,函数的参 ...

  3. poj2175

    鸣谢: http://www.cppblog.com/y346491470/articles/152317.html [题意]:一个城市有n座建筑物,每个建筑物里面有一些人,为了在战争爆发时这些人都可 ...

  4. [非技术参考]C#重写ToString方法

    C# 中的每个类或结构都隐式继承 Object 类. 因此,C# 中的每个对象都会获得 ToString 方法,此方法返回该对象的字符串表示形式. 例如,所有 int 类型的变量都有一个 ToStri ...

  5. python 学习之Windows 下的编码处理!

    问题1: Non-ASCII character '\xe9' in file 问题原因:程序编码上出现问题 解决方法:在程序头部加上代码 #-*- coding: UTF-8 -*- 设置代码编码为 ...

  6. mssql索引使用情况查询

    可通过查询dm_db_index_usage_stats表取得对应表索引被使用次数. 列名 数据类型 说明 database_id smallint 在其中定义表或视图的数据库的 ID. object ...

  7. SQL 设计心得、逗号分隔列表

    第一: 在开始编码前.主要关注数据库里要保存什么样的数据,以级最佳的数据组织方式和内在关联方式. 第二: 使用你所知的数据库特性尽可能高效的实现数据管理.如正确的索引.数据库类型.高效的select! ...

  8. 经验分享:CSS浮动(float,clear)通俗讲解 太棒了,清晰明了

    很早以前就接触过CSS,但对于浮动始终非常迷惑,可能是自身理解能力差,也可能是没能遇到一篇通俗的教程. 前些天小菜终于搞懂了浮动的基本原理,迫不及待的分享给大家. 写在前面的话: 由于CSS内容比较多 ...

  9. Android学习路线(二十)运用Fragment构建动态UI

    要在Android系统上创建一个动态或者多面板的用户界面,你须要将UI组件以及activity行为封装成模块.让它可以在你的activity中灵活地切换显示与隐藏. 你可以使用Fragment类来创建 ...

  10. BNUOJ29065鸣人的查克拉

    鸣人的查克拉 Time Limit: 1000ms Memory Limit: 65536KB 64-bit integer IO format: %lld      Java class name: ...