题目链接: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. B - 确定比赛名次

    B - 确定比赛名次 Time Limit:1000MS     Memory Limit:32768KB     64bit IO Format:%I64d & %I64u Submit S ...

  2. isalpha函数,判断字符是否是字母

    头文件:<iostream> or  <cctype>  在c语言中<ctype.h> 功能:判断一个字符是否是英文字符,是大写返回1,是小写返回2,不是英文字符返 ...

  3. C++学习之运算符重载的总结

    C++学习之运算符重载的总结              运算符重载是对已有的运算符赋予多重含义,使同一个运算符作用域不同类型的数据导致不同行为的发生,C++为运算符重载提供了一种方法,即运算符重载函数 ...

  4. Svn服务启动的两种方式

    一.svn服务器启动 › cmd命令行启动:vsvnserve -d –r 文档仓库路径 -d 后台执行 › -r 版本库的根目录 二.›Windows服务自动启动     利用xp.2000 以上的 ...

  5. 练习:一只豆瓣电影TOP250的爬虫

    练习:一只豆瓣电影TOP250爬虫 练习:一只豆瓣电影TOP250爬虫 ①创建project ②编辑items.py import scrapyclass DoubanmovieItem(scrapy ...

  6. 星际SC地图制作中生成随机位置,也包括所有需要随机的效果

    星际SC地图制作中生成随机位置,也包括所有需要随机的效果 利用单位 kakaru T 开头那个, kakaru是随机变化位置 注意kakaru的放置位置和占用格子大小,kakaru周围放上LOCATI ...

  7. IM,游戏服务端 tcp 框架整理

    Mina: Mina(Multipurpose Infrastructure for Network Applications) 是 Apache 组织一个较新的项目,它为开发高性能和高可用性的网络应 ...

  8. poj 1206

    /** 题意: 给定一序列,置换k次之后 输出其状态 置换: 考察循环节长度, 思路: 分别求出每个元素的循环节的大小,用k 模其大小,大的k次之后的位置, 输出即可 **/ #include < ...

  9. ora-01653: unable to extend table sys.aud$ by 8192 in tablespac system[转载]

    在用sqlplus user/password@truth登录数据库时报如下错误:ORA-00604: error occurred at recursive SQL level 1ORA-01653 ...

  10. qemu/kvm/qemu-kvm/virsh的区别

    转自:http://www.2cto.com/os/201305/209596.html qemu/kvm/qemu-kvm/virsh的区别   qemu是一套虚拟机管理系统,kqemu是qemu的 ...