-
时间: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;
}
时间: 2024-11-05 22:37:10