LoginSignup
0
0

More than 5 years have passed since last update.

atcoder ABC70 D問題

Posted at

条件より、ワーシャルフロイドを使えず、DFSの実装、隣接リストの実装が必要な問題だったので、解法をメモる

まず、典型的なワーシャルフロイドについて考える。
ワーシャルフロイドは、グラフがある時に(距離が全て正の値)全ての頂点について、二点間最短距離を簡単に求めるアルゴリズムである。
実装例は下の通り


        int[][] dp = new int[n][n];

        for(int i = 0;i < n;i++){               //入力
            for(int j = 0;j < n;j++){
                int x = sc.nextInt();           //xはiからjまでの距離
                dp[i][j] = x;
            }
        }

        for(int k = 0;k < n;k++){               //ワーシャルフロイド
            for(int i = 0;i < n;i++){
                for(int j = 0;j < n;j++){
                    dp[i][j] = Math.min(dp[i][j], dp[i][k]+dp[k][j]);   //各頂点の二点間最短距離を更新していく
                }
            }
        }

これは実装がすごく簡単だが、一つ難点があって、時間計算量がO(N^3)なので、頂点数が多いとすぐにTLEになってしまう。この問題でも余裕でTLEを起こしてしまうので、違う方法で最短距離を求める方法を考える。
冷静に考えると、この問題の答えは、絶対通らなければならない頂点kというものがあるので、kからの各頂点間最短距離をdfsで求めていけば良いと気づく。時間計算量も、結局全て数えてもN(全頂点数)なので、dfsの時間計算量はO(N)になる。よって、全体の時間計算量は答えなければならない問題数回+O(N)なので、O(Q + N)となり余裕で間に合う。

dfsの実装例は下の通り、


static void dfs(int p,long d){
        depth[p] = d;

        for(int i:graph.get(p).keySet()){               //現在の場所からいける場所のうち、訪れていないところならいく。
            if(!(used[i])){
                used[i] = true;
                dfs(i,  d + graph.get(p).get(i));
            }
        }
        return ;
    }
}

また、今回はグラフを作る時、隣接行列(dp[][]みたいな)を最初は考えたが、それは、明らかに問題条件よりMLEになるのでArrayListの中に、Hashmap<隣接頂点、距離>を入れることで、隣接リストを作った。このリストは、ArrayListのindexを現在の頂点とすることで、各頂点に、Hashmapを入れることで、隣接リストとして機能するようになっている。このリストの注意点としては、まずArrayListにとりあえずなんでもいいので、全てのindexにHashmapを一つ入れること。そうせずに、

graph.get(a).put(b, c);     //getで始点を指定、putで<隣接点、距離>を入れていく

のようにすると、エラーが発生する。また、この最初にHashmapを入れる際も気をつける必要がある。


 HashMap<Integer, Integer> zero = new HashMap<Integer,Integer>();
    for(int i = 0; i <= n;i++){
            zero.put(0, 0);
            graph.add(i, zero);                 //getで始点を指定、putで<隣接点、距離>を入れていく
    }

このようにArrayListの各indexに同じHashmapを入れてしまうと、どのindexに新たにHashmapを追加しても、全てのindexに対してこのHashmapが追加されることになる。よって、下のようにしなければいけない

        for(int i = 0; i <= n;i++){
            HashMap<Integer, Integer> zero = new HashMap<Integer,Integer>();
            zero.put(0, 0);
            graph.add(i, zero);                 //getで始点を指定、putで<隣接点、距離>を入れていく
        }
0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0