hdu6228-搜索&类似树的重心-Tree

http://acm.hdu.edu.cn/showproblem.php?pid=6228
这道题其实不是树的重心,只是一个搜索qwq
给定一个无根树,问你把树的任意点染成某个颜色,总共有k个颜色,然后没个颜色相互连接,把那些连接用的边搞成一个集合,总共k个集合,每个集合要求里面的边尽可能的小,问你这些集合的最大交集 有多少
思路:以前做过树的重心,树的重心满足一点,就是这个重心去掉之后,树的最大子树最小,即树尽可能的平衡,每个点如果穿过这个点连接其他子树中的点,那么路径和最大,同时,每个点到达该重心的距离和最小。
但是这道题要求的是存在一个点,这个点 的某个子树 加上这个点 构成的子树 和除了这个树 其他的点构成的树 的点 的最小值如果大于等于k,那么就可以把每个点都涂上,使这个边进入交集。
这样可以把所有的边都算一遍。

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
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;i1;i++){
              scanf("%d%d",&a,&b);
              add(b,a);
              add(a,b);
          }
          sum=0;
          dfs(1);
          printf("%d\n",sum);
    }
    return 0;
}

你可能感兴趣的:(搜索,动态规划)