题意:
给你一棵树,所有叶子节点都是客户端,其他的都是服务器,然后问你最少在多少个服务器上安装VOD能使所有的客户端都能流畅的看视频,流畅看视频的条件是每个客户端距离他最近的安装VOD的服务器的距离不能超过k,而且题目已经给你在一个服务器上安装好了VOD。
思路:
自己没想出来,说下白书上的思路,第一个就是说当遇到无根树的时候,一般情况下把无根树变成有根数会有利于问题的解决,然后这个题目就是把给定的VOD服务器变成了树根,然后我们可以根据贪心策略,先处理深度最深的,安装VOD是在当前深度最深的上面第k个父亲那安装VOD这样是为了尽可能多的去让别的客户端能用上这个VOD,然后就是模拟这个过程了,这个思路是白书上说的,我想了一阵子,只是感觉有道理,但并不能肯定他的正确性,说白了就是还没弄清楚这样为什么是对的,以后会重新编辑这篇博客。
#include<stdio.h>
#include<string.h>
#define N 1000+5
#define N_node 1000 + 5
#define N_edge 2000 + 10
typedef struct
{
int to ,next;
}STAR;
STAR E[N_edge];
int list[N_node] ,tot;
int mark[N] ,mk[N] ,deep[N];
int dis[N][N] ,mer[N];
void add(int a ,int b)
{
E[++tot].to = b;
E[tot].next = list[a];
list[a] = tot;
}
//deep mark
void DFS1(int s ,int fa)
{
int mk = 0;
for(int k = list[s] ;k ;k = E[k].next)
{
int to = E[k].to;
if(to == fa) continue;
mk = 1;
mer[to] = s;
deep[to] = deep[s] + 1;
DFS1(to ,s);
}
mark[s] = !mk;
}
//dis
void DFS2(int sss ,int now ,int s ,int fa)
{
for(int k = list[s] ;k ;k = E[k].next)
{
int to = E[k].to;
if(to == fa) continue;
dis[sss][to] = now;
DFS2(sss ,now + 1 ,to ,s);
}
}
int main ()
{
int n ,s ,k ,i ,j ,t ,a ,b;
scanf("%d" ,&t);
while(t--)
{
scanf("%d %d %d" ,&n ,&s ,&k);
memset(list ,0 ,sizeof(list)) ,tot = 1;
for(i = 1 ;i < n ;i ++)
{
scanf("%d %d" ,&a ,&b);
add(a ,b) ,add(b ,a);
}
for(i = 1 ;i <= n ;i ++) mer[i] = i;
deep[s] = 0;
DFS1(s ,-1);
for(i = 1 ;i <= n ;i ++)
{
dis[i][i] = 0;
DFS2(i ,1 ,i ,-1);
}
memset(mk ,0 ,sizeof(mk));
for(i = 1 ;i <= n ;i ++)
if(mark[i] && dis[s][i] <= k)
mk[i] = 1;
int Ans = 0;
while(1)
{
int mkid = 0 ,maxdeep = 0;
for(i = 1 ;i <= n ;i ++)
{
if(!mark[i] || mk[i]) continue;
if(maxdeep < deep[i])
maxdeep = deep[i] ,mkid = i;
}
if(!mkid) break;
Ans ++;
int maxdis = 0 ,mknode = 0;
mknode = mkid;
for(i = 1 ;i <= k ;i ++)
mknode = mer[mknode];
for(i = 1 ;i <= n ;i ++)
{
if(!mark[i] || mk[i]) continue;
if(dis[mknode][i] <= k) mk[i] = 1;
}
}
printf("%d
" ,Ans);
}
return 0;
}