Tree
Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 262144/262144 K (Java/Others)
Total Submission(s): 263 Accepted Submission(s): 178
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
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
Sample Output
1 0 1
Source
2017ACM/ICPC亚洲区沈阳站-重现赛(感谢东北大学)
一道思维题。
大致题意是,给你一棵树,让你把这些树上的节点用M种颜色染,然后问你在最优的染色方案下,相同颜色点连接的最小边集的交集最大是多少。题目可能有点难理解,看懂样例就知道了。
初始想法就是,我至少要选择M个点对,这些点对的颜色相同,要求这些点对的路径交的数量最高。那么,如果是这样的话,我首先选取树的直径,直径两端的点即为第一个点对,然后依次往里面缩小,缩小一级之后,再往周围拓展。听不懂也不要担心,因为按照此贪心策略,会得到一个WA。因为我们的相同颜色连接不只是一条路径,而是可以有多条路径,计算时候也不单只是考虑一条路径。
所以说我们换一个思路考虑。我们知道,在一棵树中,边是与点紧密连接的,而一条边要么属于最后答案所在的集合,要么不属于,那么我们要做的就是看看哪些边可以属于最后答案,哪些不属于。那么我们如何判定呢?我们从答案出发,答案的交集中的边的左右两端一定都包含M种颜色,不然肯定不是交集中的边。所以以此为判据,对于一条边,如果这条边的左右端的点数量都大于颜色的总数量,那么就说明这条边最后可以在最后结果中。统计满足条件的边数即可。具体见代码:
#include<bits/stdc++.h>
#define N 201000
#define LL long long
using namespace std;
vector<int> g[N];
int n,m,sz[N];
void getsize(int x,int fa)
{
sz[x]=1;
for(int i=0;i<g[x].size();i++)
{
int y=g[x][i];
if (y==fa) continue;
getsize(y,x); sz[x]+=sz[y];
}
}
int main()
{
int T_T;
cin>>T_T;
while(T_T--)
{
scanf("%d%d",&n,&m);
memset(g,0,sizeof(g));
for(int i=1;i<n;i++)
{
int u,v;
scanf("%d%d",&u,&v);
g[u].push_back(v);
g[v].push_back(u);
}
int ans=0;
getsize(1,0);
for(int i=1;i<=n;i++)
if (sz[i]>=m&&n-sz[i]>=m) ans++;
printf("%d\n",ans);
}
}