zoj3865
解题思路:
首先这道题求的是起点到终点之间的最短到达时间。我们可以维护一个三维的状态(x,y,direct),其中direct是光标指向的方向,可以理解为机器人robot是有方向的。光标所在的方向即为当前位置robot所面对的方向。如此一来,每一秒钟对于robot可以有四种操作:
- 朝着当前面对的方向前进一格,对应于题中按下一个按钮,机器人向对应方向移动
- 转变一次面朝的方向。对应于题中光标左移一格或者光标右移一格。
原地不动。
需要值得注意的是,每过p秒所有按钮会向右移动一格,也就是说若当前节点的时间模p为0,则应该(direct+3)%4,(direct = 0,1,2,3分别对应于左,右,上,下)。而此操作必须在此节点入队前处理,否则vis数组含义错误。
由于宽搜的性质,若取出队头节点为终点节点,即可保证其时间花费是最少。也正好说明了vis数组的必要性。
另外,对于第三种操作,即原地不动,如果原地不动后,没有发生因时间模p为0而导致的按钮右移而使状态发生改变,那么就不应该入队此新节点。此处要注意逻辑关系。
下面帖代码:
#include <cstdio>
#include <cstring>
#include <queue>
#define maxsize 12
using namespace std;
int ns, m, p;
char afx[maxsize][maxsize];
bool vis[maxsize][maxsize][4];
int sx, sy, ex, ey;
const int xx[] = {0, 0, -1, 1};
const int yy[] = { -1, 1, 0, 0};
struct node
{
int x;
int y;
int ti;
int direc;
node()
{}
node(int a, int b, int c, int d)
{
x = a;
y = b;
ti = c;
direc = d;
}
};
int bfs()
{
std::queue <node> q;
vis[sx][sy][0] = true;
node start = node(sx, sy, 0, 0);
q.push(start);
while(!q.empty())
{
node n = q.front();
q.pop();
if(n.x == ex && n.y == ey)
return n.ti;
int nx = n.x + xx[n.direc];
int ny = n.y + yy[n.direc];
node next = node(nx, ny, n.ti + 1, n.direc);
if(next.ti % p == 0)
next.direc = (next.direc + 3) % 4;
if(nx < ns && nx >= 0 && ny < m && ny >= 0 && afx[nx][ny] != '*' && !vis[nx][ny][next.direc])
{
q.push(next);
vis[nx][ny][next.direc] = true;
}
node next4 = node(n.x, n.y, n.ti + 1, (n.direc + 3) % 4);
if(next4.ti % p == 0)
next4.direc = (next4.direc + 3) % 4;
if(!vis[next4.x][next4.y][next4.direc])
{
q.push(next4);
vis[next4.x][next4.y][next4.direc] = true;
}
node next2 = node(n.x, n.y, n.ti + 1, (n.direc + 1) % 4);
if(next2.ti % p == 0)
next2.direc = (next2.direc + 3) % 4;
if(!vis[next2.x][next2.y][next2.direc])
{
q.push(next2);
vis[next2.x][next2.y][next2.direc] = true;
}
node next3 = node(n.x, n.y, n.ti + 1, n.direc);
if(next3.ti % p == 0)
{
next3.direc = (next3.direc + 3) % 4;
}
if(!vis[next3.x][next3.y][next3.direc])
{
q.push(next3);
vis[next3.x][next3.y][next3.direc] = true;
}
}
return -1;
}
void initial()
{
for(int i = 0; i < ns; i++)
for(int j = 0; j < m; j++)
{
if(afx[i][j] == '@')
{
sx = i;
sy = j;
}
else if(afx[i][j] == '$')
{
ex = i;
ey = j;
}
}
memset(vis, false, sizeof(vis));
}
int main()
{
int t;
scanf("%d", &t);
while(t--)
{
scanf("%d%d%d", &ns, &m, &p);
for(int i = 0; i < ns; i++)
scanf("%s", afx[i]);
initial();
int ans = bfs();
if(ans != -1)
printf("%d\n", ans);
else
printf("YouBadbad\n");
}
return 0;
}