题意:

  一个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;
}

 

 

posted on 2010-07-23 06:53  yongmou-  阅读(258)  评论(0编辑  收藏  举报