2023年08月23日-秋招-第三题(300分)-光芒散射

在线评测链接

题目内容

塔子哥有一些神奇的镜子,这些镜子能够吸收光芒,并在一定时间后对光芒进行散射。

塔子哥的镜子分为一级镜和二级镜,一级镜的散射速度比较快, 1 m s 1ms 1ms就可以将光芒向上下左右四个方向散射过去,而二级镜则需要 2 m s 2ms 2ms

塔子哥将这些镜子放在了一个二维矩阵中,且每个镜子的坐标均为整数。

现在,塔子哥给某一个镜子一道光芒,他想知道,最早什么时候所有镜子都能够吸收到光芒?

注:矩阵的下标从0开始

输入描述

矩阵的列数 n ( n ≤ 500 ) n(n\le500) n(n500)

矩阵的行数 m ( n ≤ 500 ) m(n\le500) m(n500)

最初获得光芒的镜子的坐标 ( i , j ) (i,j) (i,j)

接下来 m m m行,每行 n n n个数字,代表该位置镜子的等级:

如果为 0 0 0,表示该位置是一堵密不透光的墙,它足以抵挡所有的光线。

如果为 1 1 1,表示该位置的镜子散射耗时1ms

如果为 2 2 2,表示该位置的镜子散射耗时2ms

$$

$$

输出描述

一个数字代表最小时间。如果有镜子不能够吸收到光芒,那么输出-1

样例

输入

5
5
2 2
1 0 2 1 0
2 2 1 2 0
0 0 1 0 0
2 1 1 0 0
1 1 1 1 1

输出

6

思路:Dijkstra

目标是找到所有镜子接收到光芒的最早时间。因此可以想到单源最短路算法:dijkstra

首先,我们需要创建一个二维数组 dis 来存储每个镜子接收到光芒的时间,初始值设为一个较大的数。同时,我们需要一个二维数组 bk 来标记每个镜子是否已经接收到光芒,初始值设为 False

然后,我们使用优先队列 q,并将初始镜子的坐标和接收到光芒的时间(设为 0)加入队列。

接下来,我们进行Dijkstra算法。在每一步,我们取出队列中时间最早的镜子,然后更新其四个方向的镜子的接收时间。如果新的接收时间比当前的接收时间早,我们就更新接收时间,并将新的镜子加入队列。

最后,我们遍历所有的镜子,找出接收到光芒的最晚时间,即为所有镜子都能够吸收到光芒的最早时间。

时间复杂度

O ( n m l o g ( n m ) ) O(nmlog(nm)) O(nmlog(nm))

代码

C++

#include <bits/stdc++.h>
using namespace std;
typedef pair<int, int> pii;
int main() {
    vector<int> directions{-1,0,1,0,-1};
    int n, m;
    cin >> n;
    cin >> m;

    int si, sj;
    cin >> si >> sj;

    int left = 0; // 镜子的数量
    vector<vector<int>> grid(n, vector<int>(m, 0));
    for (int i = 0; i < n; i++) {
        for (int j = 0; j < m; j++) {
            cin >> grid[i][j];
            if (grid[i][j] > 0) left++;
        }
    }

    vector<vector<int>> dist(n, vector<int>(m, INT_MAX / 2)); // dist mat
    vector<vector<bool>> visited(n, vector<bool>(m, false));
    priority_queue<vector<int>, vector<vector<int>>, greater<vector<int>>> pq; // <dist, node>

    pq.push({0, si, sj});
    dist[si][sj] = 0;
    left--;

    while(!pq.empty()) {
        auto item = pq.top();
        int d = item[0], i = item[1], j = item[2];
        pq.pop();
        if (visited[i][j]) continue;
        visited[i][j] = true;

        for (int k = 0; k < 4; k++) {
            int nx = i + directions[k];
            int ny = j + directions[k + 1];
            if (nx >= 0 && nx < n && ny >= 0 && ny < m && grid[nx][ny] > 0 && dist[nx][ny] > d + grid[i][j] && !visited[nx][ny]) {
                if (dist[nx][ny] >= INT_MAX / 2) // 刚到达了一个镜子
                    left--;
                dist[nx][ny] = d + grid[i][j];
                pq.push({dist[nx][ny], nx, ny});
            } 
        }
        if (left == 0) break;
    }

    int stamp = 0;
    for (int i = 0; i < n; i++) {
        for (int j = 0; j < m; j++) {
            if (grid[i][j] > 0)
                stamp = max(stamp, dist[i][j]);
        }
    }
    if (stamp >= INT_MAX / 2) {
        stamp = -1;
    }
    cout << stamp  << endl;

    return 0;
}

python代码

import heapq
m = int(input())
n = int(input())
s , e = map(int , input().split())
a = [list(map(int , input().split())) for i in range(n)]
dis = [[10**9] * m for i in range(n)]
bk = [[False] * m for i in range(n)]
dx = [1 , -1 , 0 , 0]
dy = [0 , 0 , 1 , -1]
q = []
dis[s][e] = 0
heapq.heappush(q, [0 , s , e])
while len(q) > 0:
    u = q.pop(0)
    u = u[1:]
    if bk[u[0]][u[1]]:
        continue
    bk[u[0]][u[1]] = True
    for d in range(4):
        x = u[0] + dx[d]
        y = u[1] + dy[d]
        if x < 0 or x >= n or y < 0 or y >= m or a[x][y] == 0:
            continue 
        if dis[x][y] > dis[u[0]][u[1]] + a[u[0]][u[1]]:
            dis[x][y] = dis[u[0]][u[1]] + a[u[0]][u[1]]    
            heapq.heappush(q, [dis[x][y] , x , y])
        
ans = 0
ok = True
for i in range(n):
    for j in range(m):
        if a[i][j] != 0:
            ans = max (ans , dis[i][j])
print(ans if ans != 10**9 else -1)

Java代码

import java.util.*;

public class Main {

    public static void main(String[] args) {
        Scanner in = new Scanner(System.in);
        while (in.hasNextInt()){
            int n = in.nextInt();
            int m = in.nextInt();
            int[][] mirrors = new int[n][m];
            int initI = in.nextInt();
            int initJ = in.nextInt();
            for (int i = 0; i < n; i++) {
                for (int j = 0; j < m; j++) {
                    mirrors[i][j] = in.nextInt();
                }
            }
            int[][] times = new int[n][m];
            for (int i = 0; i < n; i++) {
                for (int j = 0; j < m; j++) {
                    times[i][j] = Integer.MAX_VALUE;
                }
            }


            Queue<int[]> queue = new PriorityQueue<>(new Comparator<int[]>() {
                @Override
                public int compare(int[] o1, int[] o2) {
                    return o1[2] - o2[2];
                }
            });//[x, y, 该点的耗时]

            int[][] visited = new int[n][m];
            queue.offer(new int[]{initI, initJ, 0});
            while (!queue.isEmpty()){
                int[] poll = queue.poll();
                int x = poll[0];
                int y = poll[1];
                int time = poll[2];
                if (x < 0 || x >= mirrors.length || y < 0 || y >= mirrors[0].length){
                    continue;
                }
                if (mirrors[x][y] == 0){
                    continue;
                }
                if (visited[x][y] == 1){
                    continue;
                }
                visited[x][y] = 1;
                times[x][y] = time;
                queue.offer(new int[]{x - 1, y, time + mirrors[x][y]});
                queue.offer(new int[]{x + 1, y, time + mirrors[x][y]});
                queue.offer(new int[]{x, y - 1, time + mirrors[x][y]});
                queue.offer(new int[]{x, y + 1, time + mirrors[x][y]});
            }
            
            int max = 0;
            for (int i = 0; i < n; i++) {
                for (int j = 0; j < m; j++) {
                    if (mirrors[i][j] != 0){
                        max = Math.max(max, times[i][j]);
                    }
                }
            }
            if (max == Integer.MAX_VALUE){
                System.out.println(-1);
            }else {
                System.out.println(max);
            }
        }
    }
    

}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

塔子哥学算法

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值