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

浙公网安备 33010602011771号