可以交题的传送门:叫我萌萌哒的传送门。
题解:
想求用最少的服务器覆盖整个客户端,我们贪心的想,对于每个服务器,我们把他放在距目前最远的的客户端k位置上。更新未满足的客户端,继续这个操作。代码给出详细解释。
#include<cstdio>
#include<cstring>
#include <vector>
#include <algorithm>
using namespace std;
const int MAXN=1010;
vector<int>gr[MAXN],nodes[MAXN];//gr存链接关系,nodes存距离关系。
int T,n,s,k;
int fa[MAXN];/父子关系
bool cover[MAXN];
void dfs(int u,int f,int d)//u为当前结点,f为前一节点,d为据根节点的距离
{
fa[u]=f;
int nc=gr[u].size();
if(nc==1&&d>k)//对于距离大于k并且是叶子节点的点,用nodes存储。
{
nodes[d].push_back(u);
}
for(int i=0;i<nc;i++)
{
int v=gr[u][i];
if(v!=f)dfs(v,u,d+1);如果不是叶子节点,重新dfs。
}
}
void dfs2(int u,int f,int d)//u为当前结点,f为前一结点,d为据这个服务器的距离。
{
cover[u]=true;
int nc=gr[u].size();
for(int i=0;i<nc;i++)
{
int v=gr[u][i];
if(v!=f&&d<k)
dfs2(v,u,d+1);
}
}
int solve(void)
{
int ans=0;
memset(cover,0,sizeof(cover));
for(int d=n-1;d>k;d--)//从距离最大的点开始考虑,找到k级祖先,在k级位置上放一个服务器。
{
for(int i=0;i<nodes[d].size();i++)
{
int u=nodes[d][i];
if(cover[u])
continue;
int v=u;
for(int j=0;j<k;j++)
v=fa[v];
dfs2(v,-1,0);
ans++;
}
}
return ans;
}
int main()
{
scanf("%d",&T);
while(T--)
{
scanf("%d%d%d",&n,&s,&k);
for(int i=0;i<=n;i++)
{
gr[i].clear();
nodes[i].clear();
}
for(int i=0;i<n-1;i++)
{
int a,b;
scanf("%d%d",&a,&b);
gr[a].push_back(b);
gr[b].push_back(a);
}
dfs(s,-1,0);//把无根树转化为有根树。
printf("%d\n",solve());
}
return 0;
}