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;
}



コメント