题目描述
有一天一位灵魂画师画了一张图,现在要你找出欧拉回路,即在图中找一个环使得每条边都在环上出现恰好一次。
一共两个子任务:
这张图是无向图。(50分)
这张图是有向图。(50分)
输入格式
第一行一个整数 t,表示子任务编号。t∈{1,2},如果 t=1 则表示处理无向图的情况,如果 t=2 则表示处理有向图的情况。
第二行两个整数 n,m,表示图的结点数和边数。
接下来 m 行中,第 i 行两个整数 vi,ui,表示第 i 条边(从 1 开始编号)。保证 1≤vi,ui≤n。
如果 t=1 则表示 vi 到 ui 有一条无向边。
如果 t=2 则表示 vi 到 ui 有一条有向边。
图中可能有重边也可能有自环。
输出格式
如果不可以一笔画,输出一行 “NO”。
否则,输出一行 “YES”,接下来一行输出一组方案。
如果 t=1,输出 m 个整数 p1,p2,…,pm。令 e=|pi|,那么 e 表示经过的第 i 条边的编号。如果 pi 为正数表示从 ve 走到 ue,否则表示从 ue 走到 ve。
如果 t=2,输出 m 个整数 p1,p2,…,pm。其中 pi 表示经过的第 i 条边的编号。
样例一
input
1
3 3
1 2
2 3
1 3
output
YES
1 2 -3
样例二
input
2
5 6
2 3
2 5
3 4
1 2
4 2
5 1
output
YES
4 1 3 5 2 6
限制与约定
1≤n≤105,0≤m≤2×105
时间限制:1s
空间限制:256MB
分析
这道题就是一道模板题,就这。(但我貌似改了n个小时)
先看这道题的数据啊,1e5,这用邻接矩阵是过不了的,会炸内存,所以这里用临界表来存。而且,要用优化的Fleury算法,本来时间复杂度是O(NM),但是可以优化,即是访问一条边(x,y)后,直接修改表头,这样会减少很多次重复搜索,时间复杂度为O(N)。
不会吧,不会吧,不会真的有人不知道Fleury吧
(注意这道题还要判断是否联通)
代码
#include <map>
#include <stack>
#include <cstdio>
#include <algorithm>
using namespace std;
const int MAXN = 2e7 + 5;
stack<int> s, ans;
bool vis[MAXN], f[MAXN], ch[MAXN];
int v[MAXN], next[MAXN], head[MAXN], d[MAXN], l[MAXN], r[MAXN];
int n, m, t, len, sum;
void Euler(int x) {
for(; head[x]; head[x] = next[head[x]]) {
int h = head[x];
if(t == 1) {
int k = (head[x] + 1) / 2;
if(!vis[k]) {
vis[k] = 1;
Euler(v[head[x]]);
if(h % 2 == 1)
ans.push(k), sum++;
else
ans.push(-k), sum++;
}
}
else if(!vis[head[x]]) {
vis[head[x]] = 1;
Euler(v[head[x]]);
ans.push(h), sum++;
}
}
}
void Write() {
if(sum < m) {
printf("NO");
return;
}
printf("YES\n");
while(!ans.empty()) {
printf("%d ", ans.top());
ans.pop();
}
}
void Check() {
int i, flag = 1;
for(i = 1; i <= n; i++)
if(!f[i] && ch[i])
flag = 0;
if(t == 1) {
for(i = 1; i <= n; i++)
if(d[i] % 2 == 1)
flag = 0;
}
else
for(i = 1; i <= n; i++) {
if(l[i] != r[i])
flag = 0;
}
if(!flag) {
printf("NO");
exit(0);
}
}
void Add(int x, int y) {
v[++len] = y; next[len] = head[x]; head[x] = len;
}
void Read() {
int i;
scanf("%d %d %d", &t, &n, &m);
for(i = 1; i <= m; i++) {
int A, B;
scanf("%d %d", &A, &B);
f[A] = f[B] = ch[A] = ch[B] = 1;
if(t == 1) {
d[A]++;
d[B]++;
Add(A, B);
Add(B, A);
}
else {
l[B]++;
r[A]++;
Add(A, B);
}
}
}
int main() {
Read();
Check();
Euler(v[1]);
Write();
return 0;
}
点个赞再走,祝你早生贵子