时间:2016-03-19 18:41:09 星期六
题目编号:[2016-03-19][UVALive][3902][Network]
题目大意:给定一个树状的图,一个服务器能覆盖k范围内的人,已知一个服务器的位置,问至少需要多少个服务器才能覆盖所有的叶子节点
分析:
- 以第一个服务器的点为根,把无根树转换为有根树
- 要使每个叶子节点都被覆盖,那么叶子节点的k级祖先内必须有一个服务器
- 要使服务器最少,服务器应该放在最远的位置
方法:
- dfs1得到每层深度的节点(k层以内的就不用记录),同时记录每个节点的父节点(为了后面求k级祖先)
- 从最深的节点开始,往上第k级祖先放置服务器,在服务器出再一次dfs2,把覆盖的点都覆盖上
#include <vector>#include <cstring>#include <cstdio>using namespace std;#define CLR(x,y) memset((x),(y),sizeof((x)))#define FOR(x,y,z) for(int (x)=(y);(x)<(z);++(x))#define FORD(x,y,z) for(int (x)=(y);(x)>=(z);--(x))const int maxn = 1000 + 10;const int maxe = maxn * (maxn - 1);int n,s,k,fa[maxn],covered[maxn];vector<int> nodes[maxn];vector<int> g[maxn];void dfs(int u,int f,int d){ fa[u] = f; int nc = g[u].size(); //叶子节点 if(nc == 1 && d > k) nodes[d].emplace_back(u); FOR(i,0,nc){ int v = g[u][i]; if(v != f) dfs(v,u,d + 1); }}void dfs2(int u,int f,int d){ covered[u] = 1; int nc = g[u].size(); FOR(i,0,nc){ int v = g[u][i]; if(v != f && d < k) dfs2(v,u,d+1); }}int solve(){ int ans = 0; CLR(covered,0); FORD(d,n-1,k + 1){ int tmpsize = nodes[d].size(); FOR(i,0,tmpsize){ int u = nodes[d][i]; if(covered[u]) continue; int v = u; FOR(j,0,k) v = fa[v]; dfs2(v,-1,0); ++ans; } } return ans;}int main(){ int t,u,v; scanf("%d",&t); while(t--){ scanf("%d%d%d",&n,&s,&k); FOR(i,1,n+1){ g[i].clear(); nodes[i].clear(); } FOR(i,0,n - 1){ scanf("%d%d",&u,&v); g[u].emplace_back(v); g[v].emplace_back(u); } dfs(s,-1,0); printf("%d\n",solve()); } return 0;}