Codeforces Round #628 (Div. 2) C

给定你一棵树,n个节点以及n-1条边。现在定义,mex(u,v)为u到v的简单路径当中没有出现的最大非负整数
求:如何给各个边标号来使得任意u,v的mex(u,v)的最大值最小(边的标号为从0到n-2)
表面上这是一个关于树的问题,实际却是一个贪心
每一次求mex(u,v)都是求简单路径当中没有出现的最小非负整数,即将问题转化成如何使小的标号分散开,尽可能不要在同一条路里面出现。
先选取最小的两个标号0,1,在树中,至少会有一条路径同时经过0和1,因此,始终会存在一条mex >= 2的路径。则我们需要使得0,1,2三个标号合理分布。
对于同时经过0,1的路径,我们需要使它的mex = 2
对于其他路径我们使它mex = 0或1
即:选中一个度数>=3的点,使它的边为0,1,2。这样0,1,2便不会再一条路径里面同时出现,实现任意的uv都有mex(u,v)的最大值为2
至于其他边的标号,随便就行

假如没有度数大于等于3的点,那么整棵树就是一条链,这样子无论怎样标号,mex的最大值都会有n+1,随便标号即可

#include 
#include 
using namespace std;
const int maxn = 1e5 + 50;
struct node
{
	int u,v,w;
}a[maxn];
int du[maxn] = {0};
int main()
{
	ios::sync_with_stdio(0);
	cin.tie(0);
	cout.tie(0);
	int n;
	cin >> n;
	for(int i = 0; i < n-1; i++)
	{
		cin >> a[i].u >> a[i].v;
		a[i].w = -1;
		du[a[i].u]++;
		du[a[i].v]++;//两点的度数都+1 
	}
	//找到一个度数大于2的点就行
	int t = 0;
	for(int i = 1; i <= n; i++)
	{
		if(du[i] > 2)
		{
			t = i;
			break;
		}
	} 
	//这时,t就是那个点 
	if(t == 0)//整棵树就是一条链,那么随便填 
	{
		for(int i = 0; i < n-1; i++)
		{
			cout << i << endl;
		}	
	} 
	else
	{
		int z = 0;
		for(int i = 0; i < n-1; i++)
		{
			if((a[i].u == t || a[i].v == t) && a[i].w == -1)
			{
				a[i].w = z;
				z++;
			}
			if(z == 3)
			break;
		}
		for(int i = 0; i < n-1; i++)
		{
			if(a[i].w == -1)
			a[i].w = z++;
		}
		for(int i = 0; i < n-1; i++)
		{
			cout << a[i].w << endl;
		}
	}
	return 0;
}

你可能感兴趣的:(Codeforces Round #628 (Div. 2) C)