Tree HDU6228

题目链接
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.
SampleInput
3
4 2
1 2
2 3
3 4
4 2
1 2
1 3
1 4
6 3
1 2
2 3
3 4
3 5
6 2
SampleOutput
1
0
1

【思路】:我们可以得知,答案肯定在树的直径上,那么我们要考虑在树的直径上的两点能否满足题目要求的条件
其实容易得知,满足条件即,子树的点数>=k 所有的点数-子树的点数>=k那么就可以知道,相连的这条边是满足条
件的,将答案加1即可,然后输出答案
因为是无根树,所以我们先找到一个树直径上的端点,再从端点开始处理出子树大小,再从端点开始搜索可以得到答案

附上代码:

#include <bits/stdc++.h>
using namespace std;
const int MAXN = 200005;
struct EDGE{
    int u, v, next;
}arr[MAXN << 1];
int head[MAXN];
int tot = 0, re;
int n, k;
void Init(){
    tot = 0;
    memset(head, -1, sizeof(head));
}
void add(int u, int v){
    arr[tot].u = u, arr[tot].v = v, arr[tot].next = head[u], head[u] = tot ++;
}
int vids[MAXN], maxs, result;
void dfs1(int u, int step){
    if(step > maxs){
        result = u;
    }
    vids[u] = 1;
    for(int i = head[u]; ~i; i = arr[i].next){
        int v = arr[i].v;
        if(!vids[v]){
            vids[v] = 1;
            dfs1(v, step + 1);
            vids[v] = 0;
        }
    }
    return ;
}
int size[MAXN];
void solve_son_size(int u){
    vids[u] = 1, size[u] = 1;
    for(int i = head[u]; ~i; i = arr[i].next){
        int v = arr[i].v;
        if(!vids[v]){
            solve_son_size(v);
            size[u] += size[v];
        }
    }
    return;
}
void solve(int u){
    vids[u] = 1;
    if(n - size[u] >= k && size[u] >= k){
        re ++;
    }
    for(int i = head[u]; ~i; i = arr[i].next){
        int v = arr[i].v;
        if(!vids[v]){
            solve(v);
        }
    }
}
int main(){
    int T;
    scanf("%d", &T);
    while(T --){
        scanf("%d%d", &n, &k);
        Init();
        for(int i = 0; i < n - 1; i ++){
            int u, v;
            scanf("%d%d", &u, &v);
            add(u, v);
            add(v, u);
        }
        maxs = 0;
        memset(vids, 0, sizeof(vids));
        dfs1(1, 0);
        //result 树的新根
        //通过树的新根,求点的子树大小
        //然后从根开始走,判断如果子树与上面的树都大于k那么答案++
        memset(vids, 0, sizeof(vids));
        memset(size, 0, sizeof(size));
        solve_son_size(result);
        re = 0;
        memset(vids, 0, sizeof(vids));
        solve(result);
        printf("%d\n", re);
    }
    return 0;
}
posted @ 2019-11-07 23:25  moxin0509  阅读(110)  评论(0编辑  收藏  举报