HDU 4375 Programmable Robot 预处理 + bfs

7 篇文章 0 订阅

题目大意:

就是现在有一个H*W的地图, H, W <= 1000, 要从S的位置到E的位置, 每次进行的操作要么是向左或者右转, 要么是向前走, 现在给出一个只有旋转的序列(只有L, R, 没有向前走的F), 现在在这个序列的任意位置加入任意数量的F问是否可以成为一个从S到达E的指令序列


大致思路:

考虑到到达位置(x, y)面朝方向为d的序列一定是在那个LR位置尽量靠前的位置更优, bfs的时候的状态只有H*W*4种

那么处理出每个LR序列的位置i到下一次面朝位置为d的对应LR序列位置为next[i][d]即可


代码如下:

Result  :  Accepted     Memory  :  86780 KB     Time  :  951 ms

/*
 * Author: Gatevin
 * Created Time:  2015/8/10 13:48:42
 * File Name: Sakura_Chiyo.cpp
 */
#include<iostream>
#include<sstream>
#include<fstream>
#include<vector>
#include<list>
#include<deque>
#include<queue>
#include<stack>
#include<map>
#include<set>
#include<bitset>
#include<algorithm>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cctype>
#include<cmath>
#include<ctime>
#include<iomanip>
using namespace std;
const double eps(1e-8);
typedef long long lint;

/*
 * 考虑到对于到达位置(x, y)朝向为d, 到达当前序列为第k个的情况, 一定比(x, y, d)且k2 > k的情况要优
 * 所以在惊醒bfs的时候要遍历的状态只有[x][y][d]一共H*W*4种
 * 由于优的是k2 > k的情况需要按照给出的LR的序列从前向后来进行bfs
 * 这里我图方便直接开了N个队列MLE了...于是换了邻接表来存储...
 * 为了转移的方便需要处理出对于给出的LR的序列当前在第i个, 要转到面朝特定方向时接下来需要转到序列中的哪个L或R才能行
 */

int dx[] = {-1, 0, 1, 0};
int dy[] = {0, 1, 0, -1};

int H, W, N;
#define next nex
char lr[1000100];//
int next[1000100][4];
int dir[1000100];
const int inf = 1e9 + 7;
char maz[1010][1010];
int vis[1010][1010][4];
int sx, sy, ex, ey;
#define mp make_pair
int cas;

int tot;//邻接表边数

struct Edge//queue MLE了换邻接表上
{
    int x, y, nex;
};

Edge edge[4000010];
int head[1000010];

void addEdge(int s, int x, int y)
{
    edge[tot].x = x, edge[tot].y = y;
    edge[tot].nex = head[s];
    head[s] = tot++;
}

bool bfs()
{
    //Q[0].push(mp(sx, sy));
    memset(head, -1, sizeof(head));
    tot = 0;
    while(sx >= 0 && sx < H && sy >= 0 && sy < W && vis[sx][sy][0] != cas && maz[sx][sy] != '#')
    {
        //Q[0].push(mp(sx, sy));
        addEdge(0, sx, sy);
        vis[sx][sy][0] = cas;
        if(sx == ex && sy == ey) return true;
        sx += dx[0], sy += dy[0];
    }
    for(int i = 0; i <= N; i++)
    {
        //while(!Q[i].empty())
        for(int j = head[i]; j + 1; j = edge[j].nex)
        {
            //int nx = Q[i].front().first, ny = Q[i].front().second;
            int nx = edge[j].x, ny = edge[j].y;
            //Q[i].pop();
            for(int d = 0; d < 4; d++)
            {
                if(next[i][d] == inf) continue;
                int tx = nx + dx[d], ty = ny + dy[d];
                while(tx >= 0 && tx < H && ty >= 0 && ty < W && vis[tx][ty][d] != cas && maz[tx][ty] != '#')
                {
                    //Q[next[i][d]].push(mp(tx, ty));
                    addEdge(next[i][d], tx, ty);
                    vis[tx][ty][d] = cas;
                    if(tx == ex && ty == ey) return true;
                    tx += dx[d], ty += dy[d];
                }
            }
        }
    }
    return false;
}


void init()
{
    dir[0] = 0;
    for(int i = 0; i < N; i++)
        dir[i + 1] = (lr[i] == 'L') ? (dir[i] + 3) % 4 : (dir[i] + 1) % 4;
    int last[4] = {inf, inf, inf, inf};
    for(int i = N; i >= 0; i--)
    {
        for(int j = 0; j < 4; j++)
            next[i][j] = last[j];
        last[dir[i]] = i;
    }
    return;
}

int main()
{
    cas = 0;
    memset(vis, 0, sizeof(vis));
    while(~scanf("%d %d %d", &H, &W, &N))
    {
        cas++;
        scanf("%s", lr);
        init();
        for(int i = 0; i < H; i++)
        {
            scanf("%s", maz[i]);
            for(int j = 0; j < W; j++)
                if(maz[i][j] == 'S') sx = i, sy = j;
                else if(maz[i][j] == 'E') ex = i, ey = j;
        }
        if(bfs()) puts("Yes");
        else puts("No");
    }
    return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值