Codeforces Round 929 (Div. 3) --- F. Turtle Mission: Robot and the Earthquake -- 题解 (最短路,难点在于对坐标的选择)

 F. Turtle Mission: Robot and the Earthquake -- 题解:

题目大意:

 

 

 

思路解析:

        这里再大概描述一下题目, 就是现在有一个机器人需要从(0,0)点前往(n-1,m-1)点去救援,但是因为他前往的路上有岩石,如果他碰上了岩石他就会被击毁,由因为发生了地震,岩石就会沿着列向上进行循环移动。机器人只能向上或者向右或者向下,问最少需要多少步,才能到达终点,如果无解输出-1.

        那么我们首先可以想到,只有机器人,岩石在动,如果我们以终点所在地为坐标轴,(以最坏情况 n == 10^3, m == 10^3来考虑这样的时间复杂度), 假如我们机器人当前在点 (i,j),因为周围的岩石在移动,那么他在 (i,j)这个点可能有 10^3的情况,即实际第i行可能表示第 0行岩石情况,可能表示第1行岩石情况....,那么对于10^6的点则共有 10^9的情况,如果使用这样的方法跑一边bfs(或者最短路)一定会超时。

        但是假如我们继续考虑上诉情况怎么优化,我们可以发现我们实际需要知道的是我们到达第 (i,j)点当前走路方案下,周围的岩石情况是怎么样的,那我们假如,把坐标系改为岩石,让机器人和终点动,那么对于 (i,j)这个点它便只有一种可能性存在了,那么这样跑bfs(或者最短路)最好情况下时间复杂度也为 10^6是可以接受的。

        在岩石坐标系下,我们再来考虑机器人怎么转移:

        向上:(在岩石坐标系下,相当于没动,所以这个向上走对于这个坐标系其实是无效的)

 向下:(在岩石坐标系下,相当于向下移动两格)

 

向右: (在固定岩石坐标下,机器人相当于往右下移动)

import java.io.*;
import java.util.*;


public class Main {
    static long mod = 998244353;
    static int n;


    public static void main(String[] args) throws IOException {
        FastScanner f = new FastScanner();
        PrintWriter w = new PrintWriter(System.out);
        int  t = f.nextInt();
        for (int o = 0; o < t; o++) {
            n = f.nextInt();
            int m = f.nextInt();
            int[][] map = new int[n][m];
            for (int i = 0; i < n; i++) {
                for (int j = 0; j < m; j++) {
                    map[i][j] = f.nextInt();
                }
            }
            boolean[][] vis = new boolean[n][m];
            PriorityQueue<Node> nodes = new PriorityQueue<>(new Comparator<Node>() {
                @Override
                public int compare(Node o1, Node o2) {
                    if(o1.va != o2.va) return o1.va - o2.va;
                    else return o2.y - o1.y;
                }
            });
            int ans = Integer.MAX_VALUE;
            nodes.add(new Node(0,0,0));
            while (!nodes.isEmpty()){
                Node cur = nodes.poll();
                if(cur.y == m - 1){
                    ans = Math.min(ans, cur.va + Math.min(Math.abs((n - 1 + cur.va) % n - cur.x), n - Math.abs((n-1 + cur.va) % n - cur.x)));
                    continue;
                }
                if (map[(cur.x + 2) % n][cur.y] == 0 && map[(cur.x + 1) % n][cur.y] == 0){
                    if (!vis[(cur.x + 2) % n][cur.y]){
                        nodes.add(new Node((cur.x + 2) % n, cur.y, cur.va+1));
                        vis[(cur.x + 2) % n][cur.y] = true;
                    }
                }
                if (cur.y + 1 < m && map[(cur.x + 1) % n][cur.y + 1] == 0){
                    if (!vis[(cur.x + 1) % n][cur.y + 1]){
                        nodes.add(new Node((cur.x + 1) % n, cur.y + 1, cur.va+1));
                        vis[(cur.x + 1) % n][cur.y + 1] = true;
                    }
                }

            }
            if (ans == Integer.MAX_VALUE) ans = -1;
            w.println(ans);
        }
        w.flush();
        w.close();

    }
    public static class Node{
        int x;
        int y;
        int va;
        public Node(int x, int y, int va){
            this.x = x;
            this.y = y;
            this.va = va;
        }
        @Override
        public boolean equals(Object o) {
            if (this == o) return true;
            if (o == null || getClass() != o.getClass()) return false;
            Node pair = (Node) o;
            return x == pair.x && y == pair.y && (va % n) == (pair.va % n);
        }

        @Override
        public int hashCode() {
            return Objects.hash(x, y, 0);
        }
    }


    private static class FastScanner {
        final private int BUFFER_SIZE = 1 << 16;
        private DataInputStream din;
        private byte[] buffer;
        private int bufferPointer, bytesRead;

        private FastScanner() throws IOException {
            din = new DataInputStream(System.in);
            buffer = new byte[BUFFER_SIZE];
            bufferPointer = bytesRead = 0;
        }

        private short nextShort() throws IOException {
            short ret = 0;
            byte c = read();
            while (c <= ' ') c = read();
            boolean neg = (c == '-');
            if (neg) c = read();
            do ret = (short) (ret * 10 + c - '0');
            while ((c = read()) >= '0' && c <= '9');
            if (neg) return (short) -ret;
            return ret;
        }

        private int nextInt() throws IOException {
            int ret = 0;
            byte c = read();
            while (c <= ' ') c = read();
            boolean neg = (c == '-');
            if (neg) c = read();
            do ret = ret * 10 + c - '0';
            while ((c = read()) >= '0' && c <= '9');
            if (neg) return -ret;
            return ret;
        }

        public long nextLong() throws IOException {
            long ret = 0;
            byte c = read();
            while (c <= ' ') c = read();
            boolean neg = (c == '-');
            if (neg) c = read();
            do ret = ret * 10 + c - '0';
            while ((c = read()) >= '0' && c <= '9');
            if (neg) return -ret;
            return ret;
        }

        private char nextChar() throws IOException {
            byte c = read();
            while (c <= ' ') c = read();
            return (char) c;
        }

        private String nextString() throws IOException {
            StringBuilder ret = new StringBuilder();
            byte c = read();
            while (c <= ' ') c = read();
            do {
                ret.append((char) c);
            } while ((c = read()) > ' ');
            return ret.toString();
        }

        private void fillBuffer() throws IOException {
            bytesRead = din.read(buffer, bufferPointer = 0, BUFFER_SIZE);
            if (bytesRead == -1) buffer[0] = -1;
        }

        private byte read() throws IOException {
            if (bufferPointer == bytesRead) fillBuffer();
            return buffer[bufferPointer++];
        }
    }
}

 

代码实现:

         

  • 29
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

Studying~

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

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

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

打赏作者

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

抵扣说明:

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

余额充值