2017ACM/ICPC亚洲区沈阳站 L.Tree (dfs)

博客围绕树节点染色问题展开,给出题目链接及描述,要求给树的节点染成k种颜色,求每种颜色集合交集的最大值。分析指出若边两侧都包含所有颜色,该边会被算入交集,给出判断边是否被选中的条件,并提及有相关代码。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=6228

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

题意

给出一棵树,可以给书上的节点染成 k 种不同的颜色,每种颜色的集合为相同颜色所经过的边,求每种颜色集合的交集的最大值。

分析

如果一条边能被算入所有颜色集合的交集,那么它的两侧肯定都分别包含所有颜色。设 sum[x] 表示以 x 为根节点的子树所包含的节点数,那么如果 sum[x] >= k && n - sum[x] >= k , x 节点到其父节点(设从 1 开始dfs)这条边必被选中。

代码
#include<bits/stdc++.h>
using namespace std;

int t,n,k;
vector<int> g[200007];
int sum[200007];
int ans;

void dfs(int x,int fa)
{
	sum[x] = 1;
	int len = g[x].size();
	for(int i=0;i<len;i++)
	{
		int to = g[x][i];
		if(fa == to) continue;
		dfs(to, x);
		sum[x] += sum[to];
	}
	if(sum[x] >= k && n - sum[x] >= k)
	{
		ans++;
	}
}

int main()
{
	scanf("%d",&t);
	while(t--)
	{
		ans = 0;
		scanf("%d%d",&n,&k);
		for(int i=1;i<=n;i++) g[i].clear();
		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);
		}
		if(n < 2 * k)
		{
			printf("0\n");
		}
		else
		{
			dfs(1, 0);
			printf("%d\n",ans);
		}
	}
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值