获取所有钥匙的最短路径

*我们可以建立一个三维组来存储当前的状态,x,y表示所处位置,key表示钥匙状态,对于现在的我来说对下面代码的<<,&,|=符号不是很熟悉,但这些是解决这题的关键。key是用二进制来表示,最开始的值为0,假设有6位二进制数,出现了某个钥匙,我们可以将相对的某个点取为1,1就代表这把钥匙是否出现。因为某个位置最多有k次的走法,所以进行广搜,到遍历的钥匙=总钥匙数就返回值

    // 定义节点结构体,包含坐标和当前持有的钥匙状态  
    struct node {  
        int x, y, key; // x,y表示坐标,key表示当前持有的钥匙状态(二进制表示)  
    };   
    const int N = 34; 
    const int K = 6;    
    const int dirs[4][2] ={{1,0},{-1,0},{0,1},{0,-1}};
    // 访问标记数组,用于记录是否访问过某个状态(坐标+钥匙状态)  
    bool vis[N][N][1 << K] = {0};  
    int sum = 0;       // 记录初始时地图上所有钥匙的集合  
    int n = a.size();  
    int m = a[0].size(); 
    queue<node> q;    
    for (int i = 0; i < n; i++) {  
        for (int j = 0; j < m; j++) {  
            if (a[i][j] == '@') { // 起点  
                q.push({i, j, 0}); // 加入队列,初始时没有钥匙  
            }  
            if (a[i][j] >= 'a' && a[i][j] <= 'f') { // 遍历所有钥匙,记录初始钥匙状态  
                sum|= 1 << (a[i][j] - 'a');  
            }  
        }  
    }  
      
    int lever = 0; // 记录当前搜索的层级(用于计算路径长度)  
    while (!q.empty()) {  
        int size = q.size(); // 当前层级的节点数  
        for (int i = 0; i < size; i++) {  
            auto [x, y, key] = q.front(); // 取出当前节点  
            q.pop();  
              
            // 遍历四个方向  
            for (int d = 0; d < 4; d++) {  
                int dx = x + dirs[d][0];  
                int dy = y + dirs[d][1];  
                  
                // 检查是否越界  
                if (dx < 0 || dx >= n || dy < 0 || dy >= m) {  
                    continue;  
                }  
                  
                char cell = a[dx][dy]; // 当前位置的字符  
                int ds = key; // 当前位置的状态(钥匙状态)  
                  
                // 如果是墙,则跳过  
                if (cell == '#') {  
                    continue;  
                }  
                  
                // 如果是门,且没有对应的钥匙,则跳过  
                if (cell >= 'A' && cell <= 'F') {  
                    if ((ds & (1 << (cell - 'A'))) == 0) {  
                        continue;  
                    }  
                }  
                // 如果是钥匙,则更新状态  
                if (cell >= 'a' && cell <= 'f') {  
                    ds |= (1 << (cell - 'a'));  
                }  
                  
                // 如果已经收集了所有钥匙,则返回当前层级+1作为最短路径长度  
                if (ds == sum) {  
                    return lever + 1;  
                }  
                  
                // 如果当前状态未被访问过,则标记并加入队列  
                if (!vis[dx][dy][ds]) {  
                    vis[dx][dy][ds] = 1;  
                    q.push({dx, dy, ds});  
                }  
            }  
        }  
        lever++; // 完成当前层级的搜索,层级+1  
    }  
      
    // 如果无法收集所有钥匙并到达终点,则返回-1  
    return -1;  
}
全部评论

相关推荐

评论
点赞
收藏
分享

创作者周榜

更多
牛客网
牛客网在线编程
牛客网题解
牛客企业服务