HDU

来源:互联网 发布:兴趣部落软件 编辑:程序博客网 时间:2024/06/18 02:33

Tree



Problem Description
Consider a un-rooted tree T which is not the biological significance of tree or plant, but a tree as an undirected graph in graph theory with n nodes, labelled from 1 to n. If you cannot understand the concept of a tree here, please omit this problem.
Now we decide to colour its nodes with k distinct colours, labelled from 1 to k. Then for each colour i = 1, 2, · · · , k, define Ei as the minimum subset of edges connecting all nodes coloured by i. If there is no node of the tree coloured by a specified colour i, Ei will be empty.
Try to decide a colour scheme to maximize the size of E1 ∩ E2 · · · ∩ Ek, and output its size.
 

Input
The first line of input contains an integer T (1 ≤ T ≤ 1000), indicating the total number of test cases.
For each case, the first line contains two positive integers n which is the size of the tree and k (k ≤ 500) which is the number of colours. Each of the following n - 1 lines contains two integers x and y describing an edge between them. We are sure that the given graph is a tree.
The summation of n in input is smaller than or equal to 200000.
 

Output
For each test case, output the maximum size of E1 ∩ E1 ... ∩ Ek.
 

Sample Input
34 21 22 33 44 21 21 31 46 31 22 33 43 56 2
 

Sample Output
101
 




题意:给你一棵树,和K种颜色,用这K种颜色去染色。然后将相同颜色的点连通所需要的最少的边作为一个集合。然后将所有颜色形成的集合做一个交,现在要找到一种染色方案,使得这个交集最大。若不使用某种颜色,那么该颜色的边集为空集。


解题思路:题目看了半天,终于看懂了,一开始往点的方向去想,毫无思路,换成边去想就好了。首先对于某种颜色染色,肯定是只染两个点最好(尽量的省点给其他颜色染)!基于这个思路,我们又想到,为了使集合最大化,肯定是染最远的两个点最好!但是有很多颜色,怎么办呢?其实对于每一条边,他有两个点,或者说两个子树,我们只要看看对于每一条边,它左右两边的子树的大小,是不是都大于K就好了。如果是,那么那条边,肯定在交集里面!(基于我们的最优算法)。所以一个深搜,答案就出来了,具体看代码。


#include<iostream>#include<deque>#include<memory.h>#include<stdio.h>#include<map>#include<string.h>#include<algorithm>#include<vector>#include<math.h>#include<stack>#include<queue>#include<set>using namespace std;typedef long long int ll;const int MAXV=200005;int k,ans;struct edge{    int v1,v2,next;}e[MAXV];int n,edge_num;int head[MAXV];int num[MAXV];//记录某个点的子树的大小void insert_edge(int v1,int v2){    e[edge_num].v1=v1;    e[edge_num].v2=v2;    e[edge_num].next=head[v1];    head[v1]=edge_num++;    e[edge_num].v1=v2;    e[edge_num].v2=v1;    e[edge_num].next=head[v2];    head[v2]=edge_num++;}void dfs(int v,int fa){    num[v]=1;    for(int i=head[v];i!=-1;i=e[i].next){        if(e[i].v2!=fa){            dfs(e[i].v2,v);            num[v]+=num[e[i].v2];                        //每条边的右边子树与左边子树的大小,左边=n-右边            if(num[e[i].v2]>=k&&n-num[e[i].v2]>=k)                ans++;        }    }}int main(){    int t;    scanf("%d",&t);    while(t--){        edge_num=0;        memset(head,-1,sizeof(head));        memset(num,0,sizeof(num));        scanf("%d%d",&n,&k);        int a,b;        for(int i=0;i<n-1;i++){            scanf("%d%d",&a,&b);            insert_edge(a,b);        }        ans=0;        dfs(1,0);        printf("%d\n",ans);    }    return 0;}