poj 1077 Eight(双向bfs)
题目链接: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)的更多相关文章
- [poj] 2549 Sumsets || 双向bfs
原题 在集合里找到a+b+c=d的最大的d. 显然枚举a,b,c不行,所以将式子移项为a+b=d-c,然后双向bfs,meet int the middle. #include<cstdio&g ...
- POJ 1077 Eight (BFS+康托展开)详解
本题知识点和基本代码来自<算法竞赛 入门到进阶>(作者:罗勇军 郭卫斌) 如有问题欢迎巨巨们提出 题意:八数码问题是在一个3*3的棋盘上放置编号为1~8的方块,其中有一块为控制,与空格相邻 ...
- 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 ...
- HDU 1043 & POJ 1077 Eight(康托展开+BFS+预处理)
Eight Time Limit: 1000MS Memory Limit: 65536K Total Submissions: 30176 Accepted: 13119 Special ...
- HDU 1043 & POJ 1077 Eight(康托展开+BFS | IDA*)
Eight Time Limit: 1000MS Memory Limit: 65536K Total Submissions: 30176 Accepted: 13119 Special ...
- POJ 3170 Knights of Ni (暴力,双向BFS)
题意:一个人要从2先走到4再走到3,计算最少路径. 析:其实这个题很水的,就是要注意,在没有到4之前是不能经过3的,一点要注意.其他的就比较简单了,就是一个双向BFS,先从2搜到4,再从3到搜到4, ...
- POJ 3126 Prime Path 解题报告(BFS & 双向BFS)
题目大意:给定一个4位素数,一个目标4位素数.每次变换一位,保证变换后依然是素数,求变换到目标素数的最小步数. 解题报告:直接用最短路. 枚举1000-10000所有素数,如果素数A交换一位可以得到素 ...
- POJ 1915-Knight Moves (单向BFS && 双向BFS 比)
主题链接:Knight Moves 题意:8个方向的 马跳式走法 ,已知起点 和终点,求最短路 研究了一下双向BFS,不是非常难,和普通的BFS一样.双向BFS只是是从 起点和终点同一时候開始搜索,可 ...
- POJ——3126Prime Path(双向BFS+素数筛打表)
Prime Path Time Limit: 1000MS Memory Limit: 65536K Total Submissions: 16272 Accepted: 9195 Descr ...
随机推荐
- win7(32 bit) + IE8 环境,IE8无法弹窗(错误提示:“此网页上的错误可能会使它无法正确运行”),有关的系统注册信息损坏——解决方法
错误截图如下: IE有关的系统注册信息损坏,导致IE无法正常弹窗. 解决办法:重新注册与IE有关的DLL文件,具体如下: 1.以管理员身份运行附件脚本(新建txt文件,将下面代码复制到txt文 ...
- C++_基础_C与C++的区别2
内容: (1)C++中的函数 (2)动态内存 (3)引用 (4)类型转换 (5)C++社区对C程序员的建议 1.C++中的函数1.1 函数的重载(1)重载的概念 在同一个作用域中,函数名相同,函数的参 ...
- poj2175
鸣谢: http://www.cppblog.com/y346491470/articles/152317.html [题意]:一个城市有n座建筑物,每个建筑物里面有一些人,为了在战争爆发时这些人都可 ...
- [非技术参考]C#重写ToString方法
C# 中的每个类或结构都隐式继承 Object 类. 因此,C# 中的每个对象都会获得 ToString 方法,此方法返回该对象的字符串表示形式. 例如,所有 int 类型的变量都有一个 ToStri ...
- python 学习之Windows 下的编码处理!
问题1: Non-ASCII character '\xe9' in file 问题原因:程序编码上出现问题 解决方法:在程序头部加上代码 #-*- coding: UTF-8 -*- 设置代码编码为 ...
- mssql索引使用情况查询
可通过查询dm_db_index_usage_stats表取得对应表索引被使用次数. 列名 数据类型 说明 database_id smallint 在其中定义表或视图的数据库的 ID. object ...
- SQL 设计心得、逗号分隔列表
第一: 在开始编码前.主要关注数据库里要保存什么样的数据,以级最佳的数据组织方式和内在关联方式. 第二: 使用你所知的数据库特性尽可能高效的实现数据管理.如正确的索引.数据库类型.高效的select! ...
- 经验分享:CSS浮动(float,clear)通俗讲解 太棒了,清晰明了
很早以前就接触过CSS,但对于浮动始终非常迷惑,可能是自身理解能力差,也可能是没能遇到一篇通俗的教程. 前些天小菜终于搞懂了浮动的基本原理,迫不及待的分享给大家. 写在前面的话: 由于CSS内容比较多 ...
- Android学习路线(二十)运用Fragment构建动态UI
要在Android系统上创建一个动态或者多面板的用户界面,你须要将UI组件以及activity行为封装成模块.让它可以在你的activity中灵活地切换显示与隐藏. 你可以使用Fragment类来创建 ...
- BNUOJ29065鸣人的查克拉
鸣人的查克拉 Time Limit: 1000ms Memory Limit: 65536KB 64-bit integer IO format: %lld Java class name: ...