给定一棵树,从树中任意结点出发,遍历m个结点,最少需要结果多少个结点,结点可以重复走。
思路:找树中最长的链,也就是树的“直径”,假设为d,如果m小于等于d,则输出m就可以了;如果m大于d,则输出d+(m-d)*2,这是因为最长链上的分支路径需要走2遍(一来一回)。那么,直径也就是最长链怎么求?先从任意一个叶子节点x出发,找到最长的路径,假设路径结尾是y节点;再以y为根,找出最长的路径,这条路径就是树的最长路径。两次dfs可以搞定了。
代码:
#include <iostream>
#include <vector>
using namespace std;
vector<int> vis;
vector<vector<int>> tree;
pair<int, int> dfs(int x) {
int mx = 0;
pair<int, int> ans;
for (int i = 0; i < tree[x].size(); ++i) {
if (!vis[tree[x][i]]) {
vis[tree[x][i]] = 1;
pair<int, int> ret = dfs(tree[x][i]);
if (ret.first > mx) {
mx = ret.first;
ans = ret;
}
}
}
if (mx) {
++ans.first;
}
else {
ans.second = x;
ans.first = 1;
}
return ans;
}
int main() {
int n, k; // n: node, k: needed node
int a, b;
freopen("in.txt", "r", stdin);
cin >> n >> k;
tree.assign(n, vector<int>());
vector<int> in(n, 0);
vis.assign(n, 0);
for (int i = 0; i < n - 1; ++i) {
cin >> a >> b;
tree[a].push_back(b);
tree[b].push_back(a);
++in[a];
++in[b];
}
int root = 0;
for (; root < n; ++root) {
if (in[root] <= 1) {
break;
}
}
pair<int, int> firstRet = dfs(9);
vis.assign(n, 0);
pair<int, int> secondRet = dfs(firstRet.second);
int len = secondRet.first;
if (len >= k) {
cout << k << endl;
}
else {
cout << len + 2 * (k - len) << endl;
}
}