バイトの競プロメモ

主に競技プログラミング

E - Cosmic Rays AtCoder Regular Contest 064

問題概略
(sx,sy)から(tx,ty)まで移動しようとしています。好きな向きへ速さ1で移動できる。
平面上にN個のバリアが貼ってあり、それぞれ半径が与えられる。
バリアは互いに重なっていることがある。
ゴールへ向かう時、バリアの外にいる時間は最短で何か。

制約
入力はすべて整数である。
−10^9≤xs,ys,xt,yt≤10^9
(xs,ys) ≠ (xt,yt)
1≤N≤1,000
−10^9≤xi,yi≤10^9
1≤ri≤10^9

解法
あるバリアへ向かう時、その中心点へ向かうのが最短である。
スタートとゴールもバリアだとみなしてやれば、バリアからバリアへ辺を貼って最短距離を求めれば良い。
上で貼った辺以外を使って行ける最短経路はない。
なぜなら、最短経路はゴールへ直線か、バリアの恩恵を最大限受けられるあるバリアへの直線だから
O(v^2)のDijkstraでやった

問題の芯
スタート、ゴールを他のものと同じにみなしてやると簡単になる

類題
D - 通勤

 public static void solve() throws Exception {
        //longを忘れるなオーバーフローするぞ
        int sx = ni();
        int sy = ni();
        int tx = ni();
        int ty = ni();
        long s = System.currentTimeMillis();
        N = ni();
        double[] x = new double[N + 2];
        double[] y = new double[N + 2];
        double[] r = new double[N + 2];
        x[0] = sx;
        y[0] = sy;
        r[0] = 0;
        x[N + 1] = tx;
        y[N + 1] = ty;
        r[N + 1] = 0;
        for (int i = 1; i < N + 1; i++) {
            x[i] = ni();
            y[i] = ni();
            r[i] = ni();
        }
 
        Dijkstra d = new Dijkstra(0, N + 2);
        for (int i = 0; i < N + 2; i++) {
            for (int j = 0; j < N + 2; j++) {
                if (i == j) continue;
                double cost = u0(Math.sqrt((x[i] - x[j]) * (x[i] - x[j]) + (y[i] - y[j]) * (y[i] - y[j])) - r[i] - r[j]);
                d.addEdge(i, j, cost);
                d.addEdge(j, i, cost);
            }
        }
        double[] dis = d.solve2();
        System.out.println(dis[N + 1]);
    }
 
 
    static class Dijkstra {
        long initValue = LINF;
        Node[] nodes;
        int s, n;
        double[] d;
        double[] d2;
        int prev[]; //最短経路の直前の頂点 -1ならnull
        int prev2[]; //2番目の最短経路の直前の頂点 -1ならnull
 
        Dijkstra(int s, int n) {
            this.s = s;
            this.n = n;
            nodes = new Node[n];
            for (int i = 0; i < n; i++)
                nodes[i] = new Node(i);
            d = new double[n];
            //todo 現状最短経路が複数ある場合に対応できていない
            //todo prev = List<LinkedList>();として複数の直前最短頂点を持とう
            prev = new int[n];
            Arrays.fill(d, initValue);
            Arrays.fill(prev, -1);
            d[s] = 0;
        }

        void addEdge(int f, int t, double c) {
            nodes[f].edges.add(new Edge(t, c));
        }
 
        //O( E ^ 2) 辺が密の時用
        double[] solve2() {
            boolean[] used = new boolean[n];
            double[][] cost = new double[n][n];
            Main.fill(cost, initValue);
 
            for (Node node : nodes) {
                for (Edge edge : node.edges) {
                    int fromId = node.id;
                    int toId = edge.toId;
                    double toCost = edge.toCost;
                    cost[fromId][toId] = toCost;
                }
            }
            while (true) {
                int v = -1;
                //まだ使われていない頂点のうち、距離が最小のものを探す。
                for (int u = 0; u < n; u++)
                    if (!used[u] && (v == -1 || d[u] < d[v])) v = u;
                if (v == -1) break;
                used[v] = true;
                for (int u = 0; u < n; u++) {
                    if (d[u] > d[v] + cost[v][u]) {
                        d[u] = d[v] + cost[v][u];
                        prev[u] = v;
                    }
                }
            }
            return d;
        }
 
        static class Dis implements Comparable<Dis> {
            //現在地点 最短距離
            int p;
            double cos;
 
            Dis(int p, double cost) {
                this.p = p;
                cos = cost;
            }
 
            public int compareTo(Dis d) {
                if (cos != d.cos) {
                    if (cos > d.cos) return 1;
                    else if (cos == d.cos) return 0;
                    else return -1;
                } else {
                    return p - d.p;
                }
            }
        }
 
        static class Node {
            int id;
            List<Edge> edges;
 
            Node(int id) {
                edges = new ArrayList<>();
                this.id = id;
            }
        }
 
        static class Edge {
            int toId;
            double toCost;
 
            Edge(int id, double cost) {
                toId = id;
                toCost = cost;
            }
 
        }
    }