题意:
一个R*C的海面,1<= R、C<=1000,上面每个点都有八个方向之一的current,顺着流走一个单位cost 0,不顺着走一个单位cost 1。计算由一个初始位置到结束位置最小的cost.
思路:
本来用A*,TLE,想想主要是因为A*考虑访问过的顶点,其实,这个题A*用的很憋屈,启发函数必须设成0。后来还是用了BFS,用两个队列,先把cost为0的全部入队列1,然后由队列1中的点扩展cost为1的点入队列2,直到队列1为空;再由队列2中点扩展cost为2的点,循环,直到找到目标节点。
一般的BFS求最短路径,需要一个记录顶点路径长度的表,但是,这种用两个队列的方式,就不需要这个表,而只用一个变量即可。代码中,用两个指针来操作队列就可以了,内层循环结束了swap一下两个指针。
代码:
#include < cstdio >
#include < queue >
using namespace std;
struct position{
int x, y;
};
#define MAX 1000
int R, C;
char mt[MAX + 1 ][MAX + 4 ];
position S, T;
int move[ 8 ][ 2 ] = {{ - 1 , 0 }, { - 1 , 1 }, { 0 , 1 }, { 1 , 1 },
{ 1 , 0 }, { 1 , - 1 }, { 0 , - 1 }, { - 1 , - 1 }};
bool is_valid( const position & v){
return ( 1 <= v.x && v.x <= R && 1 <= v.y && v.y <= C);
}
bool visited[MAX + 1 ][MAX + 1 ];
int BFS(){
for ( int i = 1 ; i <= R; ++ i)
for ( int j = 1 ; j <= C; ++ j)
visited[i][j] = false ;
int dist, cur;
position u, v;
queue < position > que1, que2;
queue < position > * popen, * pnext;
dist = 0 ;
popen = & que1;
pnext = & que2;
v = S;
while (is_valid(v) && ! visited[v.x][v.y]){
if (v.x == T.x && v.y == T.y)
return dist;
popen -> push(v);
visited[v.x][v.y] = true ;
cur = mt[v.x][v.y];
v.x += move[cur][ 0 ];
v.y += move[cur][ 1 ];
}
while ( true ){
++ dist;
while ( ! popen -> empty()){
u = popen -> front();
popen -> pop();
for ( int i = 0 ; i < 8 ; ++ i){
if (i == mt[u.x][u.y])
continue ;
v.x = u.x + move[i][ 0 ];
v.y = u.y + move[i][ 1 ];
while (is_valid(v) && ! visited[v.x][v.y]){
if (v.x == T.x && v.y == T.y)
return dist;
pnext -> push(v);
visited[v.x][v.y] = true ;
cur = mt[v.x][v.y];
v.x += move[cur][ 0 ];
v.y += move[cur][ 1 ];
}
}
}
swap(popen, pnext);
}
}
int main(){
// freopen("in", "r", stdin);
while (scanf( " %d %d " , & R, & C) != EOF){
for ( int i = 1 ; i <= R; ++ i)
scanf( " %s " , & mt[i][ 1 ]);
for ( int i = 1 ; i <= R; ++ i)
for ( int j = 1 ; j <= C; ++ j)
mt[i][j] -= ' 0 ' ;
int m, d;
scanf( " %d " , & m);
for ( int i = 0 ; i < m; ++ i){
scanf( " %d %d %d %d " , & S.x, & S.y, & T.x, & T.y);
d = BFS();
printf( " %d\n " , d);
}
printf( " \n " );
}
return 0 ;
}