• 胜利大逃亡(续) + Maze


    在之前一题的基础上加了个条件,也就是说如果当然位置的值是门,那么需要有钥匙才能经过。、
    按照前一题的思路,进行状压,设置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
    ", 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
    ", bfs());
        }
        return 0;
    }
    
  • 相关阅读:
    和时间做朋友:你一定要学的高效时间管理术
    助推:如何做出有关健康、财富与幸福的最佳决策(2017年诺贝尔经济学奖获得者理查德·泰勒作品)
    看透 : 解密身体语言隐藏的密码
    成为独角兽:海盗、梦想家、创新者如何开创并主宰新品类
    极简法则:从苹果到优步的深层简化工具
    高效15法则:谷歌、苹果都在用的深度工作发
    成功与运气:好运与精英社会的神话
    2星|《成长企业的法则》:尝试总结成功企业的模式,但是洞察力不够。
    3星|《OKR:源于英特热和谷歌的目标管理利器》:OKR原理、实施手册、实施过的公司的访谈
    gedit如何使用代码片段
  • 原文地址:https://www.cnblogs.com/Emcikem/p/13684560.html
Copyright © 2020-2023  润新知