给定你一棵树,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 <iostream>
#include <algorithm>
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;
}