胜利大逃亡(续) + Maze - 状压bfs升级版

在之前一题的基础上加了个条件,也就是说如果当然位置的值是门,那么需要有钥匙才能经过。、
按照前一题的思路,进行状压,设置vis[][][1 << 10]数组,表示当前点以及当前信息是否访问过。

如果说是小写字母,也就是钥匙,就直接把当前状态或运算一下,让当前点继承或后的值,然后加入队列即可
如果说是大写字母,也就是门,那么就需要进行判断,判断我对应的钥匙是否存在,用和运算符号,注意此时,直接继承之前的信息即可,不需要把key变成和之后的结果
如果是普通的点,就直接继承即可
传送门

#include <iostream>
#include <cstdio>
#include <queue>
#include <cstring>
using namespace std;
const int N = 25;
char s[N][N];
bool vis[N][N][1 << 11];
int dir[][2] = {1, 0, -1, 0, 0, 1, 0, -1};
int n, m, t;
int sx, sy, ex, ey;
struct Node{
    int x, y, key, step;
};
bool check(int x, int y){
    if(x < 1 || x > n || y < 1 || y > m || s[x][y] == '*') return 0;
    return 1;
}
int bfs(){
    queue<Node> q;
    Node now; now.x = sx, now.y = sy, now.key = 0, now.step = 0;
    q.push(now);
    while(!q.empty()) {
        Node u = q.front(); q.pop();
        if(u.step >= t) return -1;
        if(u.x == ex && u.y == ey) return u.step;
        for(int i = 0; i < 4; i++) {
            int xx = dir[i][0] + u.x;
            int yy = dir[i][1] + u.y;
            if(!check(xx, yy)) continue;
            Node nex;
            nex.step = u.step + 1;
            nex.x = xx, nex.y = yy;
            nex.key = u.key;
            if(s[xx][yy] >= 'a' && s[xx][yy] <= 'z') {
                int temp = s[xx][yy] - 'a';
                nex.key = u.key | (1 << temp);
            }else if(s[xx][yy] >= 'A' && s[xx][yy] <= 'Z') {
                int temp = s[xx][yy] - 'A';
                int key = u.key & (1 << temp);
                if(!key) continue;
            } 
            if(vis[xx][yy][nex.key]) continue;
            vis[xx][yy][nex.key] = 1;
            q.push(nex);
        }
    }
    return -1;
}
int main(){
    while(~scanf("%d%d%d", &n, &m, &t)) {
        memset(vis, 0, sizeof(vis));
        for(int i = 1; i <= n; i++) scanf("%s", s[i] + 1);
        for(int i = 1; i <= n; i++) {
            for(int j = 1; j <= m; j++) {
                if(s[i][j] == '@') sx = i, sy = j;
                if(s[i][j] == '^') ex = i, ey = j;
            }
        }
        printf("%d\n", bfs());
    }
    return 0;
}

传送门
maze这题也是一样的,重点在于如果去维护一个四维数组表示从(x,y)到(xx,yy)点的一些信息
然后还有个问题就是一个点可能存在多把钥匙,这个需要注意一下,甚至有起点终点是钥匙或者门的情况,都考虑到

#include <iostream>
#include <cstdio>
#include <cstring>
#include <queue>
using namespace std;
const int N = 505;
int n, m, p;
bool vis[55][55][1 << 10];
struct Node{
    int x, y, key, step;
};
int s[55][55][55][55];
int id[55][55];
int dir[][2] = {1, 0, -1, 0, 0, 1, 0, -1};
bool check(int x, int y){
    if(x < 1 || x > n || y < 1 || y > m) return 0;
    return 1;
}
int bfs(){ // start at (1, 1) ,end at (n, m)
    queue<Node> q;
    Node now; now.x = 1, now.y = 1, now.key = 0, now.step = 0;
    if(id[1][1]) now.key |= id[now.x][now.y]; // 起点有钥匙的情况
    q.push(now);
    vis[now.x][now.y][now.key] = 1;
    while(!q.empty()) {
        Node u = q.front(); q.pop();
        if(u.x == n && u.y == m) return u.step;
        for(int i = 0; i < 4; i++) {
            int xx = dir[i][0] + u.x;
            int yy = dir[i][1] + u.y;
            if(!check(xx, yy)) continue;
            if(s[u.x][u.y][xx][yy] == 0) continue; // wall,不能通过
            Node nex;
            nex.x = xx, nex.y = yy, nex.key = u.key, nex.step = u.step + 1;
            if(id[xx][yy]) { // 拿走钥匙
                nex.key |= id[xx][yy];
            }else { // door,判断是否可以通过
                if (s[u.x][u.y][xx][yy] > 0) {
                    int key = nex.key & (1 << s[u.x][u.y][xx][yy]);
                    if (!key) continue;
                }
            }
            if(vis[nex.x][nex.y][nex.key]) continue;
            vis[nex.x][nex.y][nex.key] = 1;
            q.push(nex);
        }
    }
    return -1;
}
int main(){
    //freopen("C:\\Users\\Administrator\\Desktop\\cpp_and_java\\a.txt.txt", "r", stdin);
    while(~scanf("%d%d%d", &n, &m, &p)) {
        memset(vis, 0, sizeof(vis));
        memset(id, 0, sizeof(id));
        memset(s, -1, sizeof(s));
        int k; scanf("%d", &k);
        for(int i = 1; i <= k; i++) {
            int x1, x2, y1, y2, pp;
            scanf("%d%d%d%d%d", &x1, &y1, &x2, &y2, &pp);
            s[x1][y1][x2][y2] = pp;
            s[x2][y2][x1][y1] = pp;
        }
        int S;scanf("%d", &S);
        for(int i = 1; i <= S; i++) {
            int x, y, pp;
            scanf("%d%d%d", &x, &y, &pp);
            id[x][y] |= (1 << pp); //可能存在一个点有多个钥匙
        }
        printf("%d\n", bfs());
    }
    return 0;
}
posted @ 2020-09-17 13:09  Emcikem  阅读(156)  评论(0编辑  收藏  举报