面白い問題だった。
問題概要
下の図のような木を「ユ木」と呼ぶ(正式な定義は問題文参照)。

頂点数 の木が与えられ、いくつかの頂点を削除して「ユ木」にしたい。削除する頂点の個数の最小値を求めよ。
制約
考えたこと
与えられた木において、どの頂点を「ユ木の中心」にするかで場合分けして考えることにした。
ユ木の中身にする頂点を として、
に隣接する頂点の個数を
として、それらの頂点の次数を
とする。このとき、もとの問題は次のように再解釈できる。
からいくつか選び(
個とする)、それらの最小値を
とするとき、
の値の最大値を求めよ
ここで、ユ木の頂点数は となることに注意しよう。この問題は、
を大きい順にソートする
に対して、
の値を求めて、その最大値を求める
という方法で解ける。この計算量は である。
各頂点 に対する
の値の総和は
であるから、全体の計算量は
と評価できる。
コード
#include <bits/stdc++.h> using namespace std; int main() { long long N, u, v; cin >> N; vector<vector<long long>> tree(N); vector<long long> deg(N, 0); for (int i = 0; i < N-1; i++) { cin >> u >> v, u--, v--; tree[u].push_back(v); tree[v].push_back(u); deg[u]++, deg[v]++; } long long res = N; for (int v = 0; v < N; v++) { vector<long long> d, sum; for (auto to : tree[v]) d.push_back(deg[to]); sort(d.begin(), d.end(), greater<long long>()); // vec のうち、上位 i 個を残すのを全探索 for (int i = 1; i <= d.size(); i++) { long long num = d[i-1] * i + 1; res = min(res, N - num); } } cout << res << endl; }