「一本通 3.7 例 1」欧拉回路 题解

题目描述

有一天一位灵魂画师画了一张图,现在要你找出欧拉回路,即在图中找一个环使得每条边都在环上出现恰好一次。

一共两个子任务:

这张图是无向图。(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;
} 

点个赞再走,祝你早生贵子
在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/Face_the_Blast/article/details/108135876