【AtCoder】ABC 333 D - Erase Leaves | 茶コーダーが解くAtCoder
実行時間制限: 2 sec / メモリ制限: 1024 MB / Difficulty: 704
問題概要
個の頂点からなる木が与えられ、
番目の辺は頂点
と
を結んでいる。「葉である頂点
を一つ選び、
及びそれに接続する辺を全て削除する」という操作を繰り返すとき、頂点
を削除するまでに最小で操作を何回行うことになるかを求めよ。
制約
- 入力はすべて整数。
考察
とりあえず頂点 を根とする適当な木の図を描いてみよう。

ここで、頂点 を根とする部分木を考える。
上図では赤、緑、青の3つの部分木ができた。この中から1つを残して、他の部分木の深さが深い頂点から順に削除していく。すると、頂点 の次数は
(すなわち葉) となるため、これも削除が可能となる。本問は、この段階までに削除する頂点数を最小化するというものだ。

したがって、残す部分木は頂点数が最大のものを選択することになり、答えとしては となる。
各部分木の頂点数を求める方法についてだが、これは Union Find という、グループ分けを効率的に管理できるデータ構造を使うと便利である。 AtCoder Library にもdsuという構造体名で実装されている。
頂点 を除いて辺を
mergeすることで部分木を作り、groups()で連結成分 (部分木) を列挙し、size()で連結成分の頂点数を取得できる。
コード
#include <bits/stdc++.h> #include <atcoder/all> using namespace std; using namespace atcoder; #define rep(i, start, end) for (auto i = (start); (i) < (end); (i)++) template <typename T> inline bool chmax(T &a, T b) { return ((a < b) ? (a = b, true) : (false)); } // ======================================== // int main() { int N; cin >> N; dsu d(N); rep(i, 0, N - 1) { int u, v; cin >> u >> v; if (u != 1) d.merge(u - 1, v - 1); } int max_group_size = 0; for (auto &&g : d.groups()) chmax(max_group_size, (int)g.size()); cout << N - max_group_size << endl; }
実装時間 : 25分