链接:
思路:
先把无根树转化为以s点为根的有根树
然后从深度最深的叶子节点开始枚举,如果这个叶子节点还没被覆盖掉的话,那么找它的祖先距离小于等于k的点,然后再从那个点开始dfs标记所有覆盖到的叶子节点。
#include<iostream> #include<cstdio> #include<cstring> #include<vector> #include<algorithm> using namespace std; const int Maxn = 1010; int n, s, k; struct Node{ int id, depth; friend bool operator<(const Node&lhs, const Node&rhs){ return lhs.depth > rhs.depth; } }; vector<int>G[Maxn]; vector<Node>node; bool vis[Maxn], vis2[Maxn]; int fa[Maxn]; void dfsToTree(int r, int h){ for(int i=0; i<G[r].size(); ++i)if(!vis[G[r][i]]){ vis[G[r][i]] = true; fa[G[r][i]] = r; // 保存叶子节点 if( G[G[r][i]].size()==1 ) node.push_back( (Node){G[r][i], h+1} ); dfsToTree(G[r][i], h+1); } } void dfsCover(int r, int h){ if(h < k){ for(int i=0; i<G[r].size(); ++i)if(!vis2[G[r][i]]){ vis2[G[r][i]] = true; vis[G[r][i]] = true; dfsCover(G[r][i], h+1); } } } void solve(){ // 把无根树转化成有根树,计算fa数组 memset(fa, -1, sizeof(fa)); memset(vis, 0, sizeof(vis)); vis[s] = true; node.clear(); dfsToTree(s, 0); //把叶子节点按深度排序 sort(node.begin(), node.end()); // 计算s点覆盖到的叶子结点 memset(vis, 0, sizeof(vis)); memset(vis2, 0, sizeof(vis2)); vis[s] = true; vis2[s] = true; dfsCover(s,0); int ans=0; for(int i=0; i<node.size(); ++i)if(!vis[node[i].id]){ int x=node[i].id, step=0; while(step<k && fa[x]!=-1){ x=fa[x]; ++step; } memset(vis2, 0, sizeof(vis2)); vis2[x] = true; dfsCover(x, 0); ++ans; } printf("%d\n", ans); } int main(){ int T; scanf("%d", &T); while(T--){ scanf("%d%d%d", &n, &s ,&k); for(int i=0; i<Maxn; ++i) G[i].clear(); for(int i=0; i<n-1; ++i){ int u,v; scanf("%d%d",&u,&v); G[u].push_back(v); G[v].push_back(u); } solve(); } return 0; }