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;
}