题意
给一个n个点的无向图,其中有一个隐藏点X,可以进行一组询问S来确定S是n个节点中的哪个点。S包括k个询问节点。询问返回的值也为k个值,每个值为X点到每个询问节点的最短路距离,求k最小为多少。
提示
1. 对于k个节点来说,最优的结构肯定是选择所有的叶子节点
2. 对于一个节点来说,假如它连了m条链(包括单个叶子节点),可以只标记m-1条链的叶子节点即可
3. 满足1,2条件以后,可以尝试再去询问点,发现均无法全部检测到,原因是:假如去点m-2条链,剩下的两条链,相同深度部分对于其他的节点来说是无法判断的,他们是等价的
方法
可以树形DP,一下,或者从每个叶子节点开始搜索一下,这里主要将树形DP的方法:
dp[i]代表除了i的子树部分外已经确定有询问点以后,子树i的内部确定所需要的询问点的最小值
只需要从度大于2的点开始DP一次就好了,因为假如度等于2的话,假如这个点连了一条直链,另一个点连了个非直链,那么必须得确保根节点选了以后才对,而两个非直链则不需要选根节点,因为显然根节点没连叶子节点,不需要选。而从度>2的点开始选,那么那么必有一个点子树内部是选了的,推出这个根节点是选了的,就满足了DP的定义(外部已经有确定的点),可以DP
代码
#include<bits/stdc++.h>
using namespace std;
vector<int> g[200004];
int dfs(int x, int fa) {
int ans = 0, cnt = 0;
for (auto k: g[x]) {
if (k == fa)continue;
int sum = dfs(k, x);
if (sum == 0)cnt++;
ans += sum;
}
return ans + max(0, cnt - 1);
}
void run() {
int n;
cin >> n;
for (int i = 1; i <= n; i++)g[i].clear();
for (int i = 1; i < n; i++) {
int x, y;
cin >> x >> y;
g[x].emplace_back(y);
g[y].emplace_back(x);
}
if (n == 1) {
cout << "0" << '\n';
return;
}
for (int i = 1; i <= n; i++) {
if (g[i].size() > 2) {
cout << dfs(i, 0) << '\n';
return;
}
}
cout << 1 << '\n';
}
int main() {
int t;
cin >> t;
while (t --)
run();
return 0;
}
标签:.+,int,询问,Tree,叶子,Queries,节点,DP,条链
From: https://www.cnblogs.com/4VDP/p/16812896.html