AGC001 C - Shorten Diameter

解法

解説と(ちょっとだけ)違ったので一応書いておきます.
まずBFSで全点対最短路を求めておいて,頂点 v から K より離れた頂点の数を sz[v] とします.
あとは sz[v] の大きい方から貪欲に削除していきます. v を消した時,関係のある w に対して sz[w] の値をデクリメントすれば良いです.
これは O(N^2) でできます.

ソースコード

#include <bits/stdc++.h>
using namespace std;

using ll = long long;

constexpr int INF = 1e9;

vector<int> bfs(vector<vector<int>> const& g, int s) {
    int const n = g.size();
    vector<int> d(n, INF);
    d[s] = 0;
    queue<int> que;
    que.push(s);
    while(!que.empty()) {
        int v = que.front();
        que.pop();
        for(auto to : g[v]) {
            if(d[to] != INF) {
                continue;
            }
            d[to] = d[v] + 1;
            que.push(to);
        }
    }
    return d;
}

int main() {
    int N, K;
    cin >> N >> K;
    vector<vector<int>> g(N);
    for(int i = 0; i < N - 1; ++i) {
        int a, b;
        cin >> a >> b;
        a--; b--;
        g[a].push_back(b);
        g[b].push_back(a);
    }

    vector<vector<int>> vs(N);
    vector<int> sz(N);
    for(int i = 0; i < N; ++i) {
        auto d = bfs(g, i);
        for(int j = 0; j < N; ++j) {
            if(d[j] > K) {
                vs[i].push_back(j);
                sz[i]++;
            }
        }
    }

    int res = 0;
    while(true) {
        auto it = max_element(sz.begin(), sz.end());
        if(*it == 0) {
            break;
        }
        int v = it - sz.begin();
        sz[v] = 0;
        for(auto w : vs[v]) {
            sz[w]--;
        }
        vs[v].clear();
        res++;
    }
    cout << res << endl;
}

感想

証明してないけど,sz[v] が K より大きいものをできるだけ一気に減らしたいわけで,それはつまり sz[v] が大きい方を消せばデクリメントが一気にできるから嬉しいよね,みたいな.