Codeforces 1325C - Ehab and Path-etic MEXs
题意:
给定一棵 n 个节点 n-1 条边的树
你需要给这棵树的每条边打上编号
编号从 0 开始到 n-2
定义 MEX( u,v ) 表示从节点 u 走到节点 v 的途中所经过的边中没有出现过的编号的最小非负整数
为了使得最大的 MEX( u,v ) 值最小
问应该如何编号
解题思路:
两个节点一条边直接特判
因为这是一棵树,所以我们可以从节点的方向下手
如果这棵树被构造成了一个单链,即除了首尾节点只有一个相邻节点外,其他节点都只有两个相邻节点
这种情况下不论怎么编号,答案都不会变,即最大MEX = n-1
但如果这棵树不是单链,即出现了某个节点含有三个及以上的相邻节点的话
如图
因为树上两个节点之间有且仅有一条简单路径
也就是说,对于连接同一个节点的三条边,或者是更多条边,一条简单路径最多只能包含其中的两条边
因此,根据MEX的定义
我们只要将编号 0 1 2 给定在这个节点相邻的边上即可
如果一条简单路径没有经过编号 0 的边,那么MEX的结果一定为0
如果一条简单路径经过了编号 0 的边但是没有经过编号 1 的边,那么MEX的结果一定为1
如果一条简单路径同时经过了编号 0 和编号 1 ,那么绝对不会经过编号 2 ,那么MEX的结果一定为2
这样就做到了最小化MEX最大值,即最大值为 2
另外,只要一个节点相邻节点数大于等于 3 ,都可以按照上述方式处理,只要简单路径不经过这个节点,MEX必定为 0
代码分析:
毕竟只要选相邻节点数尽量大的都行,方便起见直接对相邻节点数这个关键点进行了降序排序,pid 直接赋值为最大的那个节点的 id
只要将 0 1 2 三个编号给定在这个节点相邻边上即可
为了方便直接定义 l=0 r=n-2
让所有这个节点的相邻边从小到大赋值(主要把 0 1 2 送出去),其余边从大到小赋值(当作随机吧)
(186ms / 1000ms)
#include<bits/stdc++.h> using namespace std; struct edge { int u,v; }ar[200050]; struct node { int id,degree; bool operator < (const node& a) const { return degree>a.degree;//按照连接的边数从大到小排序 } }br[200050]; void solve() { int n,i; cin>>n; if(n==2) { cout<<"0\n"; return; } for(i=1;i<=n;i++) { br[i].id=i; br[i].degree=0; } for(i=1;i<n;i++) { cin>>ar[i].u>>ar[i].v; br[ar[i].u].degree++; br[ar[i].v].degree++; } sort(br+1,br+1+n); int pid=br[1].id,l=0,r=n-2; for(i=1;i<n;i++) { if(ar[i].u==pid||ar[i].v==pid) cout<<l++<<'\n';//相邻边从小到大排序 else cout<<r--<<'\n';//其余从大到小 } } int main() { ios::sync_with_stdio(0); cin.tie(0);cout.tie(0); solve(); return 0; }