白駿1197号最小生成ツリー


🛠 デザイン



生成ツリーとは、図形から一部の幹線を選択して作成したツリーです.
ここで、最小生成ツリー(MST)とは、生成ツリーで選択された幹線の重み付けが最小となるツリーである.
通常、ネットワーク(通信、道路、ガスパイプ)を構成(接続)する際の最低コストに主に使用されます.
MSTを解く方法には古典的なKruskalアルゴリズムとPrimアルゴリズムがある.
この問題の最大頂点数は10000個,最大幹線数は100000個であり,密集型の複数の幹線のパターンが現れる確率が高いため,Primアルゴリズムを用いるのが適切である.

💻 コード#コード#


グラフィック設定

	Graph g = new Graph(V);

        for(int i = 0; i < E; ++i){
            st = new StringTokenizer(br.readLine());
            int a = Integer.parseInt(st.nextToken());
            int b = Integer.parseInt(st.nextToken());
            int w = Integer.parseInt(st.nextToken());
            g.addEdge(new Edge(a, b, w));
            g.addEdge(new Edge(b, a, w));
        }

必要な資料構造。

        PriorityQueue<Edge> pq = new PriorityQueue<>(); // 가중치가 최소인 간선을 도출하기 위한 우선 순위 큐
        Queue<Integer> queue = new LinkedList<>(); // MST를 구성하는 정점 후보를 담고 있는 queue
        boolean[] visited = new boolean[V + 1]; // 정점 방문 체크 배열

プリフェッチアルゴリズム

        queue.add(1); // 시작 단계에서 한 정점을 기준으로 잡아준다.
        while(!queue.isEmpty()){
            int minV = queue.poll();
            visited[minV] = true;
            // 정점 minV와 간선으로 연결된 곳 중 방문하지 않은 정점을 우선 순위 큐에 추가
            for(Edge e : g.edgeList[minV]){
                if(!visited[e.end]) pq.add(e);
            }

            while(!pq.isEmpty()){
                // minE는 가중치가 가장 작은 간선
                Edge minE = pq.poll();
                //간선 minE의 목적지가 아직 방문하지 않은 곳이라면
                if(!visited[minE.end]){
                   // MST를 구성하는 정점 후보에 minE의 목적지를 담고 가중치 총 합에 가중치를 더해준다.
                    queue.add(minE.end);
                    visited[minE.end] = true;
                    sum += minE.weight;
                    break;
                }
            }
        }

        System.out.println(sum);

📝 ポスト


最初はQueueを使うとは思わなかったので、cntという変数、cntまた、既存のaと呼ばれる頂点の重み付け最小値
          for(Edge e : g.edgeList[minV]){
              if(!visited[e.end]) pq.add(e);
          }
新しい最小ウェイトが更新される可能性があるため、ループで初期化できません.
その問題を意識せずに見て答えを見ただけですが、これは最小生成木を使った最も基本的な問題で、勉強すればいろいろなところに応用できるはずです.