zoj3865

zoj3865

这里写图片描述

zoj3865

解题思路:
首先这道题求的是起点到终点之间的最短到达时间。我们可以维护一个三维的状态(x,y,direct),其中direct是光标指向的方向,可以理解为机器人robot是有方向的。光标所在的方向即为当前位置robot所面对的方向。如此一来,每一秒钟对于robot可以有四种操作:

  1. 朝着当前面对的方向前进一格,对应于题中按下一个按钮,机器人向对应方向移动
  2. 转变一次面朝的方向。对应于题中光标左移一格或者光标右移一格。
  3. 原地不动。

    需要值得注意的是,每过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;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值