http://acm.hdu.edu.cn/showproblem.php?pid=6228
这道题其实不是树的重心,只是一个搜索qwq
给定一个无根树,问你把树的任意点染成某个颜色,总共有k个颜色,然后没个颜色相互连接,把那些连接用的边搞成一个集合,总共k个集合,每个集合要求里面的边尽可能的小,问你这些集合的最大交集 有多少
思路:以前做过树的重心,树的重心满足一点,就是这个重心去掉之后,树的最大子树最小,即树尽可能的平衡,每个点如果穿过这个点连接其他子树中的点,那么路径和最大,同时,每个点到达该重心的距离和最小。
但是这道题要求的是存在一个点,这个点 的某个子树 加上这个点 构成的子树 和除了这个树 其他的点构成的树 的点 的最小值如果大于等于k,那么就可以把每个点都涂上,使这个边进入交集。
这样可以把所有的边都算一遍。
#include <iostream>
#include <stdio.h>
#include <string.h>
#include <string>
#include <stack>
#include <queue>
#include <map>
#include <set>
#include <vector>
#include <math.h>
#include <bitset>
#include <list>
#include <algorithm>
#include <climits>
using namespace std;
/*树的重心,就是刨掉一个点之后,最大子树最小。
苟神说,树形dp可以很方便的求数的重心。
*/
const int maxn=4e5+20;
struct Node{
int to;
int next;
}node[maxn];
int len;
int head[maxn];
void add(int a,int b){
node[len].to=b;
node[len].next=head[a];
head[a]=len++;
}
int m;
bool vis[maxn];
int c_tre[maxn];
int c_num2[maxn];
int sum;
void Init(){
len=0;
memset(head,-1,sizeof(head));
memset(vis,false,sizeof(vis));
memset(c_tre,0,sizeof(c_tre));
}
int kk;
int dfs(int x){
c_tre[x]=0;
vis[x]=true;
int all=0;
for(int i=head[x];i!=-1;i=node[i].next)
{ int to=node[i].to;
if(vis[to]) continue;
int ccl=dfs(to);
c_tre[x]=max(c_tre[x],ccl+1);
all+=(ccl+1);
if(min(m-ccl-1,ccl+1)>=kk){
sum++;
}
}
c_tre[x]=max(c_tre[x],m-all-1);
//c_num2[x]=m-c_tre[x]-1;
return all;
}
int main()
{ int t;
int a,b;
scanf("%d",&t);
while(t--){
scanf("%d%d",&m,&kk);
Init();
for(int i=0;i<m-1;i++){
scanf("%d%d",&a,&b);
add(b,a);
add(a,b);
}
sum=0;
dfs(1);
printf("%d\n",sum);
}
return 0;
}