K - ネットワーク敷設 / Network Installation 解説 by Solalyth


採用する \(K-1\) 個の頂点集合 \(A\) を全探索します。\(A\) に関する誘導部分グラフの最小全域木の重みを \(x\) とし、端点がそれぞれ \(A,~ \{1, \cdots, N\} \setminus A\) に属する辺の重みの最小値を \(y\) として、\(x+y\) の取りうる最小値は答えと一致します。

配列を用いる Prim 法により \(x\) の値は \(O(K^2)\) で求まります。一方の端点が \(i\) である辺のうち、重みが小さい \(K\) 個を事前に計算しておくことで、\(y\) の値は \(O(K^2)\) で求まります。以上から、全体の計算量は \(\displaystyle O\left(K^2 \binom{N}{K-1} + N^2 \log N \right)\) となり十分高速です。

ちなみに \(\displaystyle 4^2 \binom{300}{3} \approx 7.13 \times 10^7,~ 5^2 \binom{80}{4} \approx 3.95 \times 10^7\) です。

実装例 (Rust 162ms https://atcoder.jp/contests/awc0150/submissions/78947785)

use proconio::{input, marker::Usize1};
use itertools::Itertools; // for collcet_vec, combinations, min_by_key

const INF: u64 = 1<<60;

fn main() {
    input! { N: usize, M: usize, K: usize, UVW: [(Usize1, Usize1, u64); M] }
    let mut E = vec![vec![INF; N]; N];
    for (u, v, w) in UVW {
        E[u][v] = w;
        E[v][u] = w;
    }
    
    let mut Y = vec![];
    for i in 0..N {
        let mut tmp = (0..N).map(|j| (E[i][j], j)).collect_vec();
        tmp.sort();
        tmp.truncate(K);
        Y.push(tmp);
    }
    
    let mut ans = INF;
    let mut seen = vec![false; K-2];
    let mut cost = vec![INF; K-2];
    
    for A in (0..N).combinations(K-1) {
        let mut x = 0;
        seen.fill(false);
        for i in 0..K-2 { cost[i] = E[A[K-2]][A[i]]; }
        for _ in 0..K-2 {
            let i = (0..K-2).filter(|&i| !seen[i]).min_by_key(|&i| cost[i]).unwrap();
            x += cost[i];
            seen[i] = true;
            for j in 0..K-2 { cost[j] = cost[j].min(E[A[i]][A[j]]); }
        }
        
        let mut y = INF;
        for &i in &A {
            for &(w, j) in &Y[i] {
                if !A.contains(&j) { y = y.min(w); break; }
            }
        }
        
        ans = ans.min(x+y);
    }
    
    println!("{ans}");
}

投稿日時:
最終更新: