欧拉回路
第一行t表示子任务,t=1处理无向图、t=2
正文
// 原题:https://oj.yecheng.tv/p/T1527
// 题意:第一行 t 表示子任务,t = 1 处理无向图、t = 2 处理有向图,接下来给 n 个点 m 条边(可重边可自环),能一笔画就输出 YES 和 m 条边的经过顺序(无向图用负数表示反着走),否则输出 NO。
// 思路:先判度数条件(无向图所有点度为偶,有向图每点入度等于出度),再用 Hierholzer 算法跑一条欧拉回路,最后看取出的边数是否等于 m 来确认图连通。
// 1. 用栈做非递归 Hierholzer:一直沿着没走过的边往前走,走不动了就把它进栈时经过的那条边倒序记下来,最后整体翻转。
// 2. 无向图一条边拆成两个方向的有向弧,弧上带符号,顺着走记正、逆着走记负,走过一次就把整条边标记掉。
// 复杂度:O(n + m) 时间 / O(n + m) 空间
// 易错点:度数条件满足但图不连通时依然无解,必须用「最后取出的边数等于 m」再判一次,只看度数会漏掉这种情况。
// 易错点:无向图记录的是带符号的边号,两条弧要用同一个编号标记已访问,只标记一条会导致同一条边被走两次。
#include <bits/stdc++.h>
using namespace std;
struct Arc{
int to;
int id;
int sign;
};
int main(){
int t;
if(!(cin >> t)) return 0;
int n, m;
cin >> n >> m;
vector<vector<Arc> > g(n + 1);
vector<int> deg(n + 1, 0), ind(n + 1, 0), outd(n + 1, 0);
for(int i = 1; i <= m; i++){
int v, u;
cin >> v >> u;
Arc a;
a.to = u;
a.id = i;
a.sign = 1;
g[v].push_back(a);
if(t == 1){
Arc b;
b.to = v;
b.id = i;
b.sign = -1;
g[u].push_back(b);
deg[v]++;
deg[u]++;
}else{
outd[v]++;
ind[u]++;
}
}
bool ok = true;
for(int i = 1; i <= n; i++){
if(t == 1){
if(deg[i] % 2 != 0) ok = false;
}else{
if(ind[i] != outd[i]) ok = false;
}
}
if(!ok){
cout << "NO" << "\n";
return 0;
}
int s = 0;
for(int i = 1; i <= n; i++){
if(!g[i].empty()){
s = i;
break;
}
}
vector<int> ptr(n + 1, 0);
vector<char> used(m + 1, 0);
vector<int> st, ste, seq;
if(s > 0){
st.push_back(s);
ste.push_back(0);
while(!st.empty()){
int u = st.back();
while(ptr[u] < (int)g[u].size() && used[g[u][ptr[u]].id]) ptr[u]++;
if(ptr[u] == (int)g[u].size()){
if(ste.back() != 0) seq.push_back(ste.back());
st.pop_back();
ste.pop_back();
continue;
}
Arc a = g[u][ptr[u]];
ptr[u]++;
used[a.id] = 1;
st.push_back(a.to);
ste.push_back(a.sign * a.id);
}
}
if((int)seq.size() != m){
cout << "NO" << "\n";
return 0;
}
reverse(seq.begin(), seq.end());
cout << "YES" << "\n";
for(int i = 0; i < m; i++){
if(i) cout << " ";
cout << seq[i];
}
cout << "\n";
return 0;
}
一本通·提高篇的其它内容
- 活动安排
- 种树
- 喷水装置
- 加工生产调度
- 智力大冲浪
- 数列极差
- 数列分段
- 线段
- 家庭作业
- 钓鱼
- 糖果传递
- 愤怒的牛
- Best Cow Fences
- 曲线
- 数列分段 II
- 扩散
- 灯泡
- 传送带
- 数的划分
- 生日蛋糕
- 小木棍
- Addition Chains
- 埃及分数
- 平板涂色
- 质数方阵
- 靶形数独
- 电路维修
- 魔板
- Knight Moves
- 棋盘游戏
- Keyboarding
- 移动玩具
- 山峰和山谷
- Oulipo
- 图书管理
- Power Strings
- Seekthe Name, Seek the Fame
- Friends
- A Horrible Poem
- Beads
- Antisymmetry
- 门票
- 收集雪花
- 剪花布条
- Power Strings
- Radio Transmission
- OKR-Periods of Words
- 似乎在梦中见过的样子
- Censoring
- Phone List
- The XOR Largest Pair
- Nikitosh 和异或
- Immediate Decodability
- L 语言
- Secret Message 秘密信息
- 背单词
- The Xor-longest Path
- Keywords Search
- 玄武密码
- Censoring