首页 > 试题广场 >

陷阱迷宫

[编程题]陷阱迷宫
  • 热度指数:21 时间限制:C/C++ 1秒,其他语言2秒 空间限制:C/C++ 256M,其他语言512M
  • 算法知识视频讲解
一个大小为N*N,并且有若干个陷阱的迷宫,X星人现在站在迷宫左上角的起点(第1行第1列),迷宫的终点是右下角(第N行第N列)。 X星人每次可以朝上、下、左、右四个方向行走,但不允许穿越墙壁。 在迷宫中,“0”表示空地,“1”表示墙壁,“#”表示陷阱。X星人在迷宫中每行走一步需要1秒钟,但如果不幸掉入陷阱,则需要额外增加K秒的 逃脱时间。如果终点位置恰好是陷阱,也需要计算时间。 假设起点(左上角)既不是墙也不是陷阱,请问X星人从起点到终点最少需要多少时间?

输入描述:
单组输入。 第1行输入两个正整数N和K,表示迷宫的大小和逃脱陷阱需要额外增加的时间。(N<=100,K<=100) 接下来N行表示迷宫,X星人的起点是左上角,终点是右下角。


输出描述:
输出X星人从起点到终点最少需要的时间(单位:秒)。如果不能从起点到达终点则输出“No solution”。
示例1

输入

3 2
0#0
0#1
000

输出

4
#include <functional>
#include <iostream>
#include <queue>
#include <vector>
#include<climits>

using namespace std;

// 构建小根堆
struct Node {
    int cost;
    int i;
    int j;
    bool operator<(const Node& other) const{
        return cost > other.cost;
    }
};

int main() {
    int n, k;
    cin >> n >> k;
    vector<vector<char>> grid(n, vector<char>(n));
    for (int i = 0; i < n; i++) {
        for (int j = 0; j < n; j++) {
            cin >> grid[i][j];
        }
    }
    vector<vector<int>> dirs = {{-1, 0}, {1, 0}, {0, 1}, {0, -1}};
    vector<vector<int>> visited(n, vector<int>(n, INT_MAX));
    visited[0][0] = 0;
    if (grid[n - 1][n - 1] == '1') {
        cout << "No solution\n";
        return 0;
    }
    priority_queue<Node> pq;
    pq.push({0, 0, 0});
    while (!pq.empty()) {
        auto [cost, i, j] = pq.top();
        pq.pop();
        if (cost > visited[i][j]) {
            continue;
        }
        for (auto dir : dirs) {
            int di = i + dir[0];
            int dj = j + dir[1];
            if (di < 0 || dj < 0 || di >= n || dj >= n || grid[di][dj] == '1') {
                continue;
            }
            int newCost = cost + 1;
            if (grid[di][dj] == '#') {
                newCost += k;
            }
            if (visited[di][dj] > newCost) {
                pq.push({newCost, di, dj});
                visited[di][dj] = newCost;
            }
        }
    }
    if (visited[n - 1][n - 1] == INT_MAX) {
        cout << "No solution\n";
    }
    else {
        cout << visited[n - 1][n - 1] << endl;
    }
    return 0;
}
// 64 位输出请用 printf("%lld")

发表于 2025-03-31 16:27:34 回复(0)
用广度优先搜索算法可以少走重复的节点,广度优先搜索算法维护一个队列,队列中的每个元素记录的是该节点到起点的距离。用一个变量记录最小距离,当到达终点时和最小距离进行比较并更新。当算法结束后即可得到最小距离。代码实现如下:


```java
import java.util.ArrayDeque;
import java.util.Arrays;
import java.util.Scanner;

// 注意类名必须为 Main, 不要有任何 package xxx 信息
public class Main {
    public static void main(String[] args) {
        Scanner in = new Scanner(System.in);
        int N = in.nextInt(), K = in.nextInt();
        int[][] graph = new int[N][N];
        boolean visited[][] = new boolean[N][N];
        in.nextLine();
        for (int i = 0; i < N; i++) {
            String line = in.nextLine();
            // System.out.println(line);
            for (int j = 0; j < N; j++) {
                if (line.charAt(j) == '0')   graph[i][j] = 1;
                if (line.charAt(j) == '1')   graph[i][j] = -1;
                if (line.charAt(j) == '#')   graph[i][j] = K;
                visited[i][j] = false;
            }
        }

        
        // Arrays.fill(visited, false);

        // 采用广度优先搜索算法,并在搜索过程中记录节点到起点的距离
        ArrayDeque<int[]> queue = new ArrayDeque<>();
        queue.add(new int[] {0, 0, 0});
        visited[0][0] = true;
        int minDis = Integer.MAX_VALUE;
        while (!queue.isEmpty()) {
            int[] current = queue.poll();
            int x = current[0], y = current[1], dis = current[2];
            if(x == N-1 && y == N-1){
                minDis = minDis > dis ? dis : minDis;
                continue;
            }
            visited[x][y] = true;
            // System.out.println("x: " + x + ", y: " + y);
            if (x + 1 < N && visited[x + 1][y] == false && graph[x + 1][y] != -1)
                queue.add(new int[] {x + 1, y, dis + graph[x + 1][y]});
            if (x - 1 >= 0 && visited[x - 1][y] == false && graph[x - 1][y] != -1)
                queue.add(new int[] {x - 1, y, dis + graph[x - 1][y]});
            if (y + 1 < N && visited[x][y + 1] == false && graph[x][y + 1] != -1)
                queue.add(new int[] {x, y + 1, dis + graph[x][y + 1]});
            if (y - 1 >= 0 && visited[x][y - 1] == false && graph[x][y - 1] != -1)
                queue.add(new int[] {x, y - 1, dis + graph[x][y - 1]});
        }
        if(minDis == Integer.MAX_VALUE) System.out.println("No solution");
        System.out.println(minDis);
    }
}
```
发表于 2024-09-19 10:55:51 回复(2)
使用深度优先尝试所有可能,代价最小的即为答案
import java.util.Scanner;
import java.util.Arrays;

// 注意类名必须为 Main, 不要有任何 package xxx 信息
public class Main {
    static int res = Integer.MAX_VALUE;
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        // 迷宫大小
        int N = scanner.nextInt();
        // 逃脱陷阱额外时间
        int K = scanner.nextInt();
        // 地图
        int graph[][] = new int[N][N];
        // 当前点是否可达
        boolean visited[][] = new boolean[N][N];
        for(int i=0;i<N;i++){
            char[] arr = scanner.next().toCharArray();
            for(int j=0;j<N;j++){
                // 此时是起点
                if(i==0&&j==0){
                    visited[i][j] = true;
                    continue;
                }else if(arr[j]=='#'){
                    graph[i][j] = K+1;
                    visited[i][j] = true;
                }else if(arr[j]=='0'){
                    visited[i][j] = true;
                    graph[i][j] = 1; 
                }
            }  
        }
        DFS(graph,visited,0,0,N,0);
        if(res!=Integer.MAX_VALUE){
            System.out.println(res);
        }else{
            System.out.println("No solution");
        }
    }
    private static void DFS(int dp[][],boolean visited[][],int i,int j,int n,int sum){
        if(i==n-1&&j==n-1&&visited[i][j]){
            int temp = sum + dp[i][j];
            if(temp<res){
                res = temp;
            }
            return; 
        }
        if(i-1>=0 && visited[i-1][j]){
            visited[i][j] = false;
            DFS(dp,visited,i-1,j,n,sum+dp[i][j]);
            visited[i][j] = true;
        }
        if(i+1<n && visited[i+1][j]){
            visited[i][j] = false;
            DFS(dp,visited,i+1,j,n,sum+dp[i][j]);
            visited[i][j] = true;
        }
        if(j-1>=0 && visited[i][j-1]){
            visited[i][j] = false;
            DFS(dp,visited,i,j-1,n,sum+dp[i][j]);
            visited[i][j] = true;
        }
        if(j+1<n && visited[i][j+1]){
            visited[i][j] = false;
            DFS(dp,visited,i,j+1,n,sum+dp[i][j]);
            visited[i][j] = true;
        }

    } 
}


发表于 2024-08-15 14:45:25 回复(0)