PR

ABC368の復習

ABC

D問題 Minimum Steiner Tree

解法①

葉であって指定されていないものを削除していく
 ※葉=時数(辺の数)が1の頂点

指定された頂点同士をつなぐパス乗の点は消せない、という点に注目

#include <iostream>
#include <vector>
#include <queue>
#include <algorithm>
#include <atcoder/all>
#include <set>

#define INF (1LL<<30)

template<class T> inline bool chmin(T& a, T b) {
    if (a > b) { a = b; return true; }
    else return false;
}
template<class T> inline bool chmax(T& a, T b) {
    if (a < b) { a = b; return true; }
    return false;
}

long long popcount(long long n) {
    long long ans = 0;
    for (int x = 0; x <= 60; x++) if (((n >> x) & 1) == 1) ans++;
    return ans;
}

struct TreeNode {
    std::vector<int> Children;
    bool IsVisited = false;
    int num = 0;
};

int main() {
    int N, K;
    std::cin >> N >> K;
    std::vector<TreeNode> Tree;
    Tree.resize(N, TreeNode());
    for (int n = 0; n < (N-1); n++) {
        int a, b;
        std::cin >> a >> b;
        a--; b--;
        Tree[a].Children.push_back(b);
        Tree[b].Children.push_back(a);
    }

    std::vector<int> V(K);
    for (int k = 0; k < K; k++) {
        int v;
        std::cin >> v;
        v--;
        V[k] = v;
    }
    std::vector<bool> isSelected(N, false);
    for (int k = 0; k < K; k++) isSelected[V[k]] = true;

    // u:現在のノード、v:以前のノード(現在のノードにどのノードから来たか)
    auto dfs = [&](auto self, int u, int v) -> int {
        if (isSelected[u]==true) Tree[u].num++;
        for (auto child : Tree[u].Children) {
            if (child == v) continue;
            Tree[u].num += self(self, child, u);
        }
        return Tree[u].num;
        };

    dfs(dfs, V[0], -1);
    int ans = 0;
    for (int n = 0; n < N; n++) if (0 < Tree[n].num) ans++;
    std::cout << ans << std::endl;
}
スポンサーリンク

コメント

スポンサーリンク
タイトルとURLをコピーしました