题目链接: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. Winform中上传、下载文件选择打开文件的位置

    打开将要上传的文件 var fileName="";OpenFileDialog fileDialog = new OpenFileDialog(); fileDialog.Mul ...

  2. SSH框架——Sprign声明式事务

    Spring事务管理 Spring是SSH中的管理员,负责管理其它框架,协调各个部分的工作.今天一起学习一下Spring的事务管理.Spring的事务管理分为声明式跟编程式.声明式就是在Spring的 ...

  3. BHO启动IE调试

    如下图选择Web Browser Debugger, 输入启动网址

  4. 搭建Ubuntu环境中的Error [dpkg 被中断,您必须手工运行 sudo dpkg --configure -a 解决此问题][安装Flashplayer出错 ]

    //解决方法如下: sudo rm /var/cache/apt/archives/lock sudo rm /var/lib/dpkg/lock sudo dpkg -r flashplugin-i ...

  5. android-SQLite 和 Content

    SQLite 游标(Cursor)相当于指向底层数据中结果集的指针,而不是提取和返回结果值的副本,是在结果集中对位置(行)进行控制的管理方式. moveToFirst:把游标移动到查询结果的第一行 m ...

  6. AAU账号分割

    import win.ui; import fsys.dlg; import string.list; /*DSG{{*/ var winform = win.form(text="aard ...

  7. bootstrap 更改container 的width

    参考:http://stackoverflow.com/questions/15884102/bootstrap-how-do-i-change-the-width-of-the-container ...

  8. C++使用OLE高速读写EXCEL的源码

    我的代码参考的地方是这儿,再次感谢原作者 http://blog.csdn.net/gyssoft/archive/2007/04/29/1592104.aspx 我根据自己的需要做了整理,干净了一点 ...

  9. Min Stack (LeetCode) tweak it to avoid Memory Limit Exceeded

    class MinStack { public: void push(int x) { if(values.empty()) { values.push_back(x); min_indices.pu ...

  10. CATransition类动画

    - (void)leftClick { [UIView beginAnimations:nil context:nil]; //display mode, slow at beginning and  ...