zoukankan      html  css  js  c++  java
  • java练习 bfs POJ_3669 Meteor Shower

    题目描述

    题目地址:https://vjudge.net/problem/POJ-3669

    倒霉蛋Bessie现在坐标原点(0,0),现在要有陨石砸下来,寻找Bessie到达安全地点(陨石砸不到的点)所需的最短时间。

    此次共有M (1 ≤ M ≤ 50,000)颗流星来袭,流星i将在时间点Ti (0 ≤ Ti ≤ 1,000) 袭击点 (Xi, Yi) (0 ≤ Xi ≤ 300; 0 ≤ Yi ≤ 300)。每颗流星都将摧毁落点及其相邻四点的区域。

    Bessie在0时刻时处于原点,且只能行于第一象限,以平行与坐标轴每秒一个单位长度的速度奔走于未被毁坏的相邻(通常为4)点上。在某点被摧毁的刹那及其往后的时刻,她都无法进入该点。

    Input - 输入

    第1行: 一个整数: M
    第2..M+1行: 第i+1行包含由空格分隔的三个整数: Xi, Yi, and Ti
    

    Output - 输出

    仅一行: Bessie寻得安全点所花费的最短时间,无解则为-1。
    

    样例:

    Input:
    4
    0 0 2
    2 1 2
    1 1 2
    0 3 5
    
    Output:
    5
    
    分析:
    0时刻   1时刻  2时刻  3时刻  4时刻  5时刻
    (0,0)->(0,1)->(0,2)->(0,3)->(0,4)->(0,5)
                              ->(1,3)->(1,4)
                                     ->(2,3)
    
    5时刻的三个点是最近的安全点。在纸上画一下就能理解。
    

    题目分析

    看到最短就想到bfs。最简单的地图只有两种状态,可达和不可达。

    这题稍微复杂的是:

    1. 判断点是否可达。有一个时间的概念,在某一时刻及该时刻后,某点不可达。
    2. 不可达点有范围影响。
    3. 终点(安全点)不是指定地点。

    解决思路:

    1. map不用0、1来标记,而是用 int t 标记。-1代表安全,不会被陨石摧毁;t代表在t时刻被摧毁。
    2. 输入陨石落点时,对上下左右的点也进行标记。
    3. map标记为-1的点就是安全地点,即终点。

    细节见代码

    代码

    
    import java.util.LinkedList;
    import java.util.Queue;
    import java.util.Scanner;
    
    class Point {
        public int x, y, t;
    
        public Point() {
        }
    
        public Point(int x, int y, int t) {
            this.x = x;
            this.y = y;
            this.t = t;
        }
    }
    
    public class Main {
        private static final Scanner SC = new Scanner(System.in);
        private static final int[] DX = {0, 0, -1, 1, 0};
        private static final int[] DY = {-1, 1, 0, 0, 0};
        private static int row = 303, col = 303; // 根据陨石坠落范围[0,300]设置地图范围,大一点点就可以,大太多也没用,因为求的是最短
        private static int[][] map = new int[row][col];
    
        /**
         * 初始化地图
         * 初始化值为-1,代表安全地点
         */
        public static void initMap() {
            for (int i = 0; i < row; i++) {
                for (int j = 0; j < col; j++) {
                    map[i][j] = -1;
                }
            }
        }
    
        /**
         * 记录陨石对地图的破坏情况
         */
        public static void recordMeteor() {
            int meteors = SC.nextInt();
            int r, c, t, tr, tc;
            // 记录陨石击中的时间
            while (meteors-- > 0) {
                // r,c为坐标
                r = SC.nextInt();
                c = SC.nextInt();
                // t为陨石最早击中的时刻(最早摧毁时间)
                // 部分地点会被重复摧毁,在该点被摧毁的刹那及其往后的时刻,都不能再到达,所以要保留最早摧毁时间
                t = SC.nextInt();
                // 陨石有溅射效果,落点和上下左右,共5个点都会被摧毁
                for (int i = 0; i < 5; i++) {
                    tr = r + DX[i];
                    tc = c + DY[i];
                    // 陨石也有可摧毁的范围
                    if (tr < 0 || tr > 301 || tc < 0 || tc > 301) {
                        continue;
                    }
                    if (map[tr][tc] == -1) {
                        map[tr][tc] = t;
                    } else {// 保留最早被摧毁的时间
                        map[tr][tc] = Math.min(map[tr][tc], t);
                    }
                }
    
            }
        }
    
        public static int bfs() {
    
            // 天胡,起点就是安全的
            if (map[0][0] == -1) {
                return 0;
            }
    
            // 反向天胡,没来及跑就被炸了
            if (map[0][0] == 0) {
                return -1;
            }
    
            Queue<Point> queue = new LinkedList<Point>();
            queue.add(new Point(0, 0, 0));
    
            while (!queue.isEmpty()) {
                Point cur = queue.poll();
                int tr, tc;
                // 安全了,返回
                if (map[cur.x][cur.y] == -1) {
                    return cur.t;
                }
                // 当前点不可达,抛弃这个状态
                if (map[cur.x][cur.y] <= cur.t) {
                    continue;
                }
                // 当前点可达,但是还得跑
                for (int i = 0; i < 4; i++) {
                    tr = cur.x + DX[i];
                    tc = cur.y + DY[i];
    
                    if (0 <= tr && tr < row && 0 <= tc && tc < col) {
                        // 下一步是安全地点
                        if (map[tr][tc] == -1) {
                            return cur.t + 1;
                        }
                        // 下一步可以到达,但是还得接着跑
                        if (cur.t < map[tr][tc]) {
                            // 把来时的路炸了,不走回头路
                            map[cur.x][cur.y] = cur.t;
                            queue.add(new Point(tr, tc, cur.t + 1));
                        }
                    }
    
                }
            }
            return -1;
        }
    
        public static void main(String[] args) {
    
            // 初始化地图
            initMap();
    
            // 记录陨石对地图的破坏情况
            recordMeteor();
    
            // bfs
            int ans = bfs();
            System.out.println(ans);
        }
    }
    

    参考

    1. https://blog.csdn.net/queque_heiya/article/details/104086766
    2. https://blog.csdn.net/a1097304791/article/details/101617157
    3. https://www.cnblogs.com/sky-stars/p/11185040.html
    4. https://www.cnblogs.com/demian/p/6152963.html

    大佬们都是C/C++

    请批评指正!
  • 相关阅读:
    bzoj:2423: [HAOI2010]最长公共子序列
    bzoj:3994:vijos1949: [SDOI2015]约数个数和
    bzoj4332;vijos1955:JSOI2012 分零食
    bzoj:1726: [Usaco2006 Nov]Roadblocks第二短路
    bzoj:1724: [Usaco2006 Nov]Fence Repair 切割木板
    bzoj:1666: [Usaco2006 Oct]Another Cow Number Game 奶牛的数字游戏
    bzoj:1230: [Usaco2008 Nov]lites 开关灯
    bzoj:1941: [Sdoi2010]Hide and Seek
    bzoj:1699;poj 3264: [Usaco2007 Jan]Balanced Lineup排队
    bzoj 1705;poj 3612:[Usaco2007 Nov]Telephone Wire 架设电话线
  • 原文地址:https://www.cnblogs.com/vastian/p/12783158.html
Copyright © 2011-2022 走看看