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;
}

 

posted @ 2020-03-15 02:08  StelaYuri  阅读(323)  评论(0编辑  收藏  举报