HDU5040- Instrusive(BFS+记忆化搜索)

题目链接


题意:给定一张图,Matt要从M移动到T取偷东西,N,W,S,E表示这些位置有监控器,字母表示这些监控器的初始方向,并且每一秒顺时针旋转90度。现在Matt每移动一格需要花一秒,但是如果当前他所在的位置或者他要去的位置被监控器监视,那么如果他要移动,就必须躲在箱子里移动,时间需要花费3秒。或者也可以选择不移动,躲在箱子里1秒,问说Matt最少花费多少时间移动到T。

思路:借鉴的是小伙伴的想法,先预处理整张图,用二进制表示在一个周期(4S)内每个格子是否会被监控器监控到,之后状态要多开一维,表示4S一个周期,然后进行状态转移。

代码:

#include <iostream>
#include <cstdio>
#include <cstring>
#include <queue>
#include <algorithm>

using namespace std;

const int MAXN = 505;
const int INF = 0x3f3f3f3f;
const int dx[] = {-1, 0, 1, 0};
const int dy[] = {0, 1, 0, -1}; 

struct node{
    node(int xx, int yy, int tt) {
        x = xx; 
        y = yy;
        t = tt;
    }
    int x, y, t;
};

char map[MAXN][MAXN];
int g[MAXN][MAXN], d[MAXN][MAXN][5];
int n, sx, sy, ex, ey;

int change(char c) {
    if (c == 'N') return 0;
    if (c == 'E') return 3;
    if (c == 'S') return 2;
    if (c == 'W') return 1;
    return -1;
}

int bfs(int x, int y, int t) {
    queue<node> q;
    node s(x, y, 0);
    q.push(s); 
    memset(d, INF, sizeof(d));
    d[s.x][s.y][s.t] = 0;
    int ans = INF; 
    while (!q.empty()) {
        node u = q.front(); 
        q.pop();
        node v = u;               
        
        if (v.x == ex && v.y == ey)
            ans = min(ans, d[v.x][v.y][v.t]);

        v.t = (v.t + 1) % 4;
        if (d[v.x][v.y][v.t] > d[u.x][u.y][u.t] + 1) {
            d[v.x][v.y][v.t] = d[u.x][u.y][u.t] + 1;
            q.push(v);
        }
        for (int i = 0; i < 4; i++) {
            node v = u; 
            v.x = u.x + dx[i];
            v.y = u.y + dy[i];
            int step = 0;
            if (v.x < 0 || v.x >= n || v.y < 0 || v.y >= n || g[v.x][v.y] == -1) continue;
            if ((g[u.x][u.y] & (1<<u.t)) || (g[v.x][v.y] & (1<<u.t))) {
                v.t = (v.t + 3) % 4; 
                step = 3;
            }
            else {
                v.t = (v.t + 1) % 4; 
                step = 1;
            }
            if (d[v.x][v.y][v.t] > d[u.x][u.y][u.t] + step) {
                d[v.x][v.y][v.t] = d[u.x][u.y][u.t] + step;
                q.push(v);
            }
        }
    }
    return ans;
}

int main() {
    int cas, t = 1;    
    scanf("%d", &cas);
    while (cas--) {
        scanf("%d", &n);  
        memset(g, 0, sizeof(g));
        memset(map, 0, sizeof(map));
        for (int i = 0; i < n; i++) {
            scanf("%s", map[i]);
            for (int j = 0; j < n; j++) {
                if (map[i][j] == 'M') {
                    sx = i; 
                    sy = j;
                }
                else if (map[i][j] == 'T') {
                    ex = i;
                    ey = j;
                }
                else if (map[i][j] == '#')
                    g[i][j] = -1;
                else if (change(map[i][j]) != -1) {
                    g[i][j] = 15; 
                    for (int k = 0; k < 4; k++) {
                        int tx = i + dx[k]; 
                        int ty = j + dy[k];
                        if (tx < 0 || tx >= n || ty < 0 || ty >= n || map[tx][ty] == '#') continue;
                        g[tx][ty] |= (1<<((change(map[i][j]) + k) % 4));
                    } 
                }
            }
        }

        printf("Case #%d: ", t++);
        int ans = bfs(sx, sy, 0);
        if (ans >= INF)
            printf("-1\n");
        else 
            printf("%d\n", ans);
    }
    return 0;
}



用记忆化搜索差点就超时了,所以用BFS+优先队列会更好,思想其实是差不多的。


#include <iostream>
#include <cstdio>
#include <cstring>
#include <queue>
#include <algorithm>

using namespace std;

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

int vis[N][N][5], b[N][N][5];
char g[N][N];

int n, sx, sy, ex, ey;

struct node{
    node(int xx, int yy, int dd) {
        x = xx; 
        y = yy;
        d = dd;
    }
    int x, y, d;
    friend bool operator < (node a, node b) {
        return a.d > b.d; 
    }
};

int bfs(int x,int y) {
    priority_queue <node> q ;
    node s(x, y, 0);
    q.push(s) ;
    memset(vis,0,sizeof(vis)) ;
    vis[x][y][0] = 1 ;
    while(!q.empty()) {
        node u = q.top() ;
        q.pop();

        if(u.x == ex && u.y == ey) 
            return u.d ; 

        for(int i = 0 ;i < 5 ;i++) {
            int tx = u.x + dx[i] ;
            int ty = u.y + dy[i] ;

            if(tx < 0 || tx >= n || ty < 0 || ty >= n || g[tx][ty] == '#')continue ;

            node p = u;
            if(b[tx][ty][u.d%4] || b[u.x][u.y][u.d%4]) {
                if(tx == u.x && ty == u.y && !vis[tx][ty][(u.d+1)%4]) {
                    p.d++ ;
                    vis[tx][ty][p.d%4]=1 ;
                    q.push(p) ;
                }
                else if(!vis[tx][ty][(u.d+3)%4]) {
                    p.x=tx;
                    p.y=ty ;
                    p.d += 3 ;
                    vis[tx][ty][p.d%4]=1 ;
                    q.push(p) ;
                }
            }
            else if(!vis[tx][ty][(u.d+1)%4]) {
                p.x=tx;
                p.y=ty;
                p.d++ ;
                vis[tx][ty][p.d%4]=1 ;
                q.push(p) ;
            }
        }
    }
    return -1 ;
}

int main() {
    int cas, t = 1;
    scanf("%d", &cas);
    while (cas--) {
        scanf("%d", &n);
        for (int i = 0; i < n; i++)   
            scanf("%s", g[i]);

        memset(b, 0, sizeof(b));
        for (int i = 0; i < n; i++)
            for (int j = 0; j < n; j++) {
                if (g[i][j] == 'M') {
                    sx = i; 
                    sy = j; 
                } 
                else if (g[i][j] == 'T') {
                    ex = i; 
                    ey = j; 
                }
                else if (g[i][j] == 'N') {
                    b[i][j][0] = b[i][j][1] = b[i][j][2] = b[i][j][3] = 1;
                    if (i - 1 >= 0) b[i - 1][j][0] = 1;
                    if (j + 1 < n) b[i][j + 1][1] = 1;
                    if (i + 1 < n) b[i + 1][j][2] = 1;
                    if (j - 1 >= 0) b[i][j - 1][3] = 1;
                }
                else if (g[i][j] == 'W') {
                    b[i][j][0] = b[i][j][1] = b[i][j][2] = b[i][j][3] = 1;
                    if (j - 1 >= 0) b[i][j - 1][0] = 1;
                    if (i - 1 >= 0) b[i - 1][j][1] = 1;
                    if (j + 1 < n) b[i][j + 1][2] = 1; 
                    if (i + 1 < n) b[i + 1][j][3] = 1;
                }
                else if (g[i][j] == 'S') {
                    b[i][j][0] = b[i][j][1] = b[i][j][2] = b[i][j][3] = 1;
                    if (i + 1 < n) b[i + 1][j][0] = 1;
                    if (j - 1 >= 0) b[i][j - 1][1] = 1;
                    if (i - 1 >= 0) b[i - 1][j][2] = 1;
                    if (j + 1 < n) b[i][j + 1][3] = 1; 
                }
                else if (g[i][j] == 'E') {
                    b[i][j][0] = b[i][j][1] = b[i][j][2] = b[i][j][3] = 1;
                    if (j + 1 < n) b[i][j + 1][0] = 1; 
                    if (i + 1 < n) b[i + 1][j][1] = 1;
                    if (j - 1 >= 0) b[i][j - 1][2] = 1;
                    if (i - 1 >= 0) b[i - 1][j][3] = 1;
                }
            }
        printf("Case #%d: %d\n", t++, bfs(sx, sy));
    }
    return 0;
}


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值