之前写过这道题目的博客,用c++实现的前向星博客地址~~
感觉自己不是很理解vector的存储方式,所以用结构体去存图(没有学过c++,所以不敢轻易用自己不熟悉的东西),结果WA,后来在和大佬的沟通中才知道原来这是用vector去实现的前向星(以存储边的方式存储图),百度找了下链式前向星,自己理解之后,终于把这道题用自己喜欢的方式写过了~~撒花~~
#include<stdio.h>
#include<algorithm>
#include<string.h>
using namespace std;
const int maxn = 1010;
int fa[maxn],cover[maxn],cnt,cnt2;
int head[maxn],head2[maxn];
struct node{
int to,next;
};
struct node edge[maxn*100],Node[maxn*100];
int n,s,k;
void Add(int u,int to)//存储无根树的邻接表
{
edge[cnt].to = to;
edge[cnt].next = head[u];
head[u] = cnt ++;
return;
}
void Add2(int u,int to)//存储叶节点的邻接表
{
Node[cnt2].to = to;
Node[cnt2].next = head2[u];
head2[u] = cnt2++;
return;
}
void dfs(int u,int f,int d)//建以s为根的有根树
{
int i,v,l,sum = 0,flag=0;
fa[u] = f;
for(i = head[u];i != -1;i = edge[i].next)
{
sum ++;
if(sum > 1)//如果u连接的结点超过1个,说明不是叶结点
{
flag = 1;
}
}
if(!flag&&d > k)
Add2(d,u);//距离根s超过k的叶结点存入邻接表
for(i = head[u]; i != -1; i = edge[i].next)
{
v = edge[i].to;
if(v != f)
dfs(v,u,d+1);//继续建树
}
return;
}
void dfs2(int u,int f,int d)
{
int i,v;
cover[u] = 1;//在k范围内的结点,全部覆盖
for(i = head[u]; i != -1; i = edge[i].next )
{
v = edge[i].to;
if(v != f&&d < k)//如果v结点仍在k范围内,则继续覆盖
dfs2(v,u,d+1);
}
return;
}
int find()
{
int i,j,v,ans,l,u,m;
ans = 0;
for(i = n-1; i > k; i--)
{
for(j = head2[i]; j != -1; j = Node[j].next)//遍历覆盖每个叶结点i所连接的结点
{
v = Node[j].to;
if(cover[v])//如果已经覆盖过,跳过
continue;
u = v;
for(m = 0; m < k; m ++)//找到该结点v的k级祖先
u = fa[u];
dfs2(u,-1,0);
ans ++;//记录服务器个数
}
}
return ans;
}
int main()
{
int t,i,j,a,b;
scanf("%d",&t);
while(t--)
{
scanf("%d",&n);
scanf("%d%d",&s,&k);
memset(fa,0,sizeof(fa));//存结点间的关系
memset(cover,0,sizeof(cover));//记录结点是否被覆盖
memset(head,-1,sizeof(head));
memset(head2,-1,sizeof(head2));
cnt = cnt2 = 0;//边的编号
for(i = 0; i < n-1; i ++)
{
scanf("%d%d",&a,&b);
Add(a,b);
Add(b,a);
}
dfs(s,-1,0);
printf("%d\n",find());
}
return 0;
}