公式

D - 通信ネットワークの構築 / Construction of a Communication Network 解説 by MMNMM


負荷指数を最小にするような \(S\) は、(全拠点を連結にした上で)\(\displaystyle\sum _ {i\in S}c _ i\) を最小にするような \(S\) です。

証明

そのような \(S\) はクラスカル法によって得られます。

クラスカル法を実行する様子を考えると、候補 \(\displaystyle\argmax _ {i\in S}c _ i\) は最後に追加される辺で、それ以前に追加された辺からなる \(2\) つの連結成分 \(U,V\) を繋ぐものです。

クラスカル法のアルゴリズムから、\(U\) と \(V\) を繋ぐ辺はすべて \(\displaystyle\max _ {i\in S}c _ i\) 以上のコストを持ちます。

よって、すべての拠点間で通信可能なネットワークは \(\displaystyle\max _ {i\in S}c _ i\) 以上のコストのケーブルを含まなければなりません。

よって、\(\displaystyle\sum _ {i\in S}c _ i\) を最小にする \(S\) は同時に \(\displaystyle\max _ {i\in S}c _ i\) を最小にする \(S\) であることが示されたので、これが最小の負荷指数を与えることがわかりました。

よって、最小全域木を求める十分高速なアルゴリズムを使って \(S\) を求め、負荷指数を計算することでこの問題を解くことができました。

実装例は以下のようになります。

#include <iostream>
#include <vector>
#include <algorithm>
#include <atcoder/dsu>
using namespace std;

int main() {
    int N, M, K;
    cin >> N >> M >> K;
    vector<tuple<int, int, int>> edges(M);
    for (auto& [u, v, c] : edges) {
        cin >> u >> v >> c;
        --u; // 0-indexed にしておく
        --v;
    }
    // 辺をコストの昇順にソート
    ranges::sort(edges, {}, [](auto p){return get<2>(p);});

    // 最小全域木を作り、コストの総和と最大値を求める
    atcoder::dsu uf(N);
    long sum_cost = 0, max_cost = 0;
    for (auto [u, v, c] : edges) {
        if (!uf.same(u, v)) {
            uf.merge(u, v);
            sum_cost += c;
            max_cost = max<long>(c, max_cost);
        }
    }
    cout << sum_cost + K * max_cost << endl;
    return 0;
}
from atcoder.dsu import DSU


N, M, K = map(int, input().split())

edges = []
for i in range(M):
    u, v, c = map(int, input().split())
    edges.append((u - 1, v - 1, c)) # 0-indexed にしておく
# 辺をコストの昇順にソート
edges.sort(key=lambda e: e[2])

# 最小全域木を作り、コストの総和と最大値を求める
uf = DSU(N)
sum_cost = 0
max_cost = 0
for u, v, c in edges:
    if not uf.same(u, v):
        uf.merge(u, v)
        sum_cost += c
        max_cost = max(c, max_cost)

print(sum_cost + K * max_cost)

投稿日時:
最終更新: