uva 10047
2013-12-14 20:02
288 查看
这是一道复合状态的迷宫搜索题 。
对vis数组的理解: 以前一直以为这只是一个标记每个点事否走过的数组 , 其实这只是片面的认识 , 它标记的不是一个点 ,
而是一个“状态” , 状态和点是不一样的 , 点是单一的 , 而状态不只是表示一个点 , 更是表示这个点所处在的状态 。
这个题要把方向 , 颜色 , 点 ,一起看成一个综合的状态 , 那就意味着要定义一个四维数组 。
用bfs有两种方法 :
1、用优先队列 , 那么就可以减小很多内存的消耗 , 且速度也更快 。
用优先队列 , 可以不记录只改变方向点不变的状态 , 就是让这个点“改变方向+按这个方向走向下一个点”,一步完成 。如果这样的话 ,
会产生一种情况 , 就是同一次bfs遍历到的点 , 所花的时间是不一样的。所以 , 如果按照这个情况bfs下去 ,
并且取第一次到时间为最优时间,这样是有漏洞的 。
2、不用优先队列 , 但是只改变方向的状态也必须要记录 , 这样同时遍历到的点所花的时间就是一样的了 ,bfs最先找到的也就是最优的解
。
第一种情况的代码:
#include
#include
#include
#include
using namespace std ;
const int maxn = 25 + 10 ;
//一个状态的五个属性,坐标,方向,步数
struct Node { int x ; int y ; int d ; int s ; int c ; } node1 ,
node2 ;
//优先队列
struct cmp
{
bool
operator () (const Node a, const Node b)
{
return a.s > b.s;
}
};
priority_queue ,cmp > q ;
//queue < Node > q ;
//一般队列不能用,因为队首可能不是最优的,因为当你得到一个状态扩展出来的所有状态时,
//你需要且只需要最优的那一个,所以优先队列成为必然的选择(当然你也可以在所有状态中找到当前最优的一个状态,嘿嘿)
char map[maxn][maxn] ;
bool visit[maxn][maxn][5][4] ;//标记状态数组
int r , c ;//行列
int bx , by , ex , ey ;//开始位置与终点位置
int ans ;//最小步数
int flag ;//标记是否有解
int dx[] = { -1 , 1 , 0 , 0 } ;//控制x方向
int dy[] = { 0 , 0 , -1 , 1 } ;//控制y方向
int dd[] = { 0 , 1 , 2 , 3 } ;//北,南,西,东(上,下,左,右)
//初始化
void init()
{
bx = by = ex
= ey = 0 ;
ans = 0 ;
flag = 0 ;
while( !
q.empty() ) q.pop() ;
memset( map
, 0 , sizeof( map ) ) ;
memset(
visit , 0 , sizeof( visit ) ) ;
for( int i =
0 ; i < r ; ++i )
{
for( int j = 0 ; j < c ; ++j )
{
cin >> map[i][j] ;
if( map[i][j] == 'S' )
{ bx = i ; by = j ; }
if( map[i][j] == 'T' )
{ ex = i ; ey = j ; }
}
}
return
;
}
//判断状态是否出现过
bool is_ok( int x , int y , int cc , int d )
{
if( x < 0
|| y < 0 || x >= r || y >= c || map[x][y] == '#' ||
visit[x][y][cc][d] )
return false
;
return true
;
}
//得到步数
int get_step( int nd , int d , int s )
{
if( d == 0
&& nd == 1 ) return s + 2 ;
else if( d
== 1 && nd == 0 ) return s + 2 ;
else if( d
== 2 && nd == 3 ) return s + 2 ;
else if( d
== 3 && nd == 2 ) return s + 2 ;
else return
s + 1 ;
}
//判断是否为解
bool is_ans( int x , int y , int cc )
{
if( x != ex
|| y != ey || cc )
return false
;
return true
;
}
//广度优先搜索
void bfs()
{
//初始化队首
node1.x = bx
, node1.y = by , node1.c = 0 , node1.s = 0 , node1.d = 0 ;
q.push(
node1 ) ;
visit[bx][by][node1.c][node1.d] = true ;
while( !
q.empty() )
{
node1 = q.top() ;
q.pop() ;
int x = node1.x ;
int y = node1.y ;
int c = node1.c ;
int s = node1.s ;
int d = node1.d ;
for( int i = 0 ; i < 4 ; ++i )
{
int nd = dd[i] ;
对vis数组的理解: 以前一直以为这只是一个标记每个点事否走过的数组 , 其实这只是片面的认识 , 它标记的不是一个点 ,
而是一个“状态” , 状态和点是不一样的 , 点是单一的 , 而状态不只是表示一个点 , 更是表示这个点所处在的状态 。
这个题要把方向 , 颜色 , 点 ,一起看成一个综合的状态 , 那就意味着要定义一个四维数组 。
用bfs有两种方法 :
1、用优先队列 , 那么就可以减小很多内存的消耗 , 且速度也更快 。
用优先队列 , 可以不记录只改变方向点不变的状态 , 就是让这个点“改变方向+按这个方向走向下一个点”,一步完成 。如果这样的话 ,
会产生一种情况 , 就是同一次bfs遍历到的点 , 所花的时间是不一样的。所以 , 如果按照这个情况bfs下去 ,
并且取第一次到时间为最优时间,这样是有漏洞的 。
2、不用优先队列 , 但是只改变方向的状态也必须要记录 , 这样同时遍历到的点所花的时间就是一样的了 ,bfs最先找到的也就是最优的解
。
第一种情况的代码:
#include
#include
#include
#include
using namespace std ;
const int maxn = 25 + 10 ;
//一个状态的五个属性,坐标,方向,步数
struct Node { int x ; int y ; int d ; int s ; int c ; } node1 ,
node2 ;
//优先队列
struct cmp
{
bool
operator () (const Node a, const Node b)
{
return a.s > b.s;
}
};
priority_queue ,cmp > q ;
//queue < Node > q ;
//一般队列不能用,因为队首可能不是最优的,因为当你得到一个状态扩展出来的所有状态时,
//你需要且只需要最优的那一个,所以优先队列成为必然的选择(当然你也可以在所有状态中找到当前最优的一个状态,嘿嘿)
char map[maxn][maxn] ;
bool visit[maxn][maxn][5][4] ;//标记状态数组
int r , c ;//行列
int bx , by , ex , ey ;//开始位置与终点位置
int ans ;//最小步数
int flag ;//标记是否有解
int dx[] = { -1 , 1 , 0 , 0 } ;//控制x方向
int dy[] = { 0 , 0 , -1 , 1 } ;//控制y方向
int dd[] = { 0 , 1 , 2 , 3 } ;//北,南,西,东(上,下,左,右)
//初始化
void init()
{
bx = by = ex
= ey = 0 ;
ans = 0 ;
flag = 0 ;
while( !
q.empty() ) q.pop() ;
memset( map
, 0 , sizeof( map ) ) ;
memset(
visit , 0 , sizeof( visit ) ) ;
for( int i =
0 ; i < r ; ++i )
{
for( int j = 0 ; j < c ; ++j )
{
cin >> map[i][j] ;
if( map[i][j] == 'S' )
{ bx = i ; by = j ; }
if( map[i][j] == 'T' )
{ ex = i ; ey = j ; }
}
}
return
;
}
//判断状态是否出现过
bool is_ok( int x , int y , int cc , int d )
{
if( x < 0
|| y < 0 || x >= r || y >= c || map[x][y] == '#' ||
visit[x][y][cc][d] )
return false
;
return true
;
}
//得到步数
int get_step( int nd , int d , int s )
{
if( d == 0
&& nd == 1 ) return s + 2 ;
else if( d
== 1 && nd == 0 ) return s + 2 ;
else if( d
== 2 && nd == 3 ) return s + 2 ;
else if( d
== 3 && nd == 2 ) return s + 2 ;
else return
s + 1 ;
}
//判断是否为解
bool is_ans( int x , int y , int cc )
{
if( x != ex
|| y != ey || cc )
return false
;
return true
;
}
//广度优先搜索
void bfs()
{
//初始化队首
node1.x = bx
, node1.y = by , node1.c = 0 , node1.s = 0 , node1.d = 0 ;
q.push(
node1 ) ;
visit[bx][by][node1.c][node1.d] = true ;
while( !
q.empty() )
{
node1 = q.top() ;
q.pop() ;
int x = node1.x ;
int y = node1.y ;
int c = node1.c ;
int s = node1.s ;
int d = node1.d ;
for( int i = 0 ; i < 4 ; ++i )
{
int nd = dd[i] ;
相关文章推荐
- STL中优先队列的用法
- 并查集及其路径的压缩
- 求欧拉回路的路径 dfs的一种新运用
- poj 2676
- poj 2531
- poj 2251
- poj 2488
- 网络流 SAP优化算法 (…
- 网络流之Dinic算法
- 基于增广路的网络流算法
- poj 1789 最小生成树
- poj 1469
- poj 3041二分匹配
- scanf和cin的区别 (效率的差距)
- 匈牙利算法
- poj 1062 最短路
- poj 1860 最短路
- poj 3259 最短路(带负环)
- poj 3080
- poj 1035