2025 ICPC武汉邀请赛 E 题思路分享(欧拉回路)

题意

给定无向图,给每条边染色,要求同一个点不能连有 \(\gt 2\) 条相同颜色的边,给出一种染色方案,最小化每个点连有不同颜色边的数量之和.

\(2\le n,m \le 2\cdot 10^5\).

思路

发现单元环染同样颜色是最优的,因此考虑欧拉回路拆环的做法,虚拟出节点 \(0\),所有奇度数的点都向 \(0\) 连边,这样所有点都是偶度数.

先用 \(Hierholzer\) 算法求出一个欧拉回路序列,需要包含点和边. 遍历这个序列,用两个栈分别存边和点,当遍历到点已在栈中说明成环,弹栈染色即可.

时间复杂度 \(\mathcal{O}(n+m)\).

代码

//author:kzssCCC

#include <bits/stdc++.h>
using namespace std;
using ll = long long;


void solve(){
    int n,m;
    cin >> n >> m;

    vector<vector<pair<int,int>>> adj(n+1);
    vector<int> ing(n+1);
    for (int i=1;i<=m;i++){
        int u,v;
        cin >> u >> v;
        adj[u].emplace_back(i,v);
        adj[v].emplace_back(i,u);
        ing[u]++,ing[v]++;
    }

    int tot = m+1;
    for (int i=1;i<=n;i++){
        if (ing[i]&1){
            adj[0].emplace_back(tot,i);
            adj[i].emplace_back(tot++,0);
            ing[i]++,ing[0]++;
        }
    }

    vector<bool> vis(tot,false);
    vector<int> cur(n+1);
    vector<pair<int,int>> euler;

    function<void(int,int)> dfs = [&](int u,int ed){
        int len = adj[u].size();
        while (cur[u]<len){
            auto& [id,v] = adj[u][cur[u]++];
            if (!vis[id]){
                vis[id] = true;
                dfs(v,id);
            }
        }
        euler.emplace_back(u,ed);
    };

    for (int i=0;i<=n;i++){
        if (cur[i]<adj[i].size()){
            dfs(i,-1);
        }
    }

    reverse(euler.begin(),euler.end());
    vector<int> color(tot);
    int col = 1;
    stack<int> stkE,stkV;
    vector<bool> in_stk(n+1,false);

    for (auto& [u,ed]:euler){
        if (in_stk[u]){
            color[ed] = col;
            while (!stkV.empty() && stkV.top()!=u){
                int V = stkV.top();
                stkV.pop();
                int E = stkE.top();
                stkE.pop();

                color[E] = col;
                in_stk[V] = false;
            }
            col++;
        }
        else{
            stkE.push(ed);
            stkV.push(u);
            in_stk[u] = true;
        }
    }

    for (int i=1;i<=m;i++){
        cout << color[i] << ' ';
    }
    cout << '\n';
}

int main(){
    ios::sync_with_stdio(false);
    cin.tie(0);
    
    int t = 1;
    cin >> t;
    while (t--) solve();

    return 0;
}
posted @ 2026-07-23 11:42  kzssCCC  阅读(9)  评论(0)    收藏  举报