在讲题之前我把有关欧拉回路的知识点先整理出来,如下:

知识锦囊

欧拉路径: 在图 G 中包含每条边各一次的路径

欧拉回路:在图 G 中从起点出发包含每条边各一次且最终回到起点的路径(就是如果一个欧拉路径的起始点相同,那就是一个欧拉回路)

欧拉图: 含有欧拉回路的图

半欧拉图: 含有欧拉路径,没有欧拉回路的图

简单路径:   除起点和终点可以相同以外,所有简单路径上的点都只被经过一次(只出现一次)

简单回路:  起点和终点相同的简单路径

总的来说就是简单路径是每个点只访问一次,欧拉路径是每条边只访问一次

现在我们来看看如何判断一个图是否为欧拉图:

分为无向图和有向图来考虑

若为无向图,则需满足条件:

  1. 这个图必须连通(这显而易见)
  2. 每个顶点的度数为偶数(因为每个点“进”“出”的次数相同,所以必为偶数)

(若将 条件2 改为只有两个点的度数为奇数,那就是判断一个半欧拉图了)

若为有向图,则需满足条件:

  1. 这个图的基图是连通的(所谓基图,就是有向图不考虑边的方向,当做无向图来看)
  2. 每个顶点的出度和入度相等

(若将 条件2 改为只有两个点的出度和入度不一样,且起点 -->出度=入度+1,终点 -- > 出度=入度 - 1,那就是判半欧拉图)

那么判断倒是很容易,如果要输出欧拉回路的路径呢,这个怎么搞?

据说有两种方法可以达到目的,但我们只讲更优秀的那一个就够了,另外一个的话,嘿嘿,可以去这里看一下,讲的很好,下面的我也是摘自这个博客,真的写的好棒

基本(套圈)法

  首先从一个节点(v0)出发,随便往下走(走过的边需要标记一下,下次就别走了),当走到不能再走的时候,所停止的点必然也是起点(因为所有的点的度数都是偶数,能进去肯定还会出来,再者中间有可能再次经过起点,但是如果起点还能继续走,那么就要继续往下搜索,直到再次回来时不能往下搜索为止),然后停止时,走过的路径形成了一个圈,但因为是随便走的,所以可能有些边还没走就回来了,那些剩下的边肯定也会形成一个或者多个环,然后可以从刚才终止的节点往前回溯,找到第一个可以向其他方向搜索的节点(vi),然后再以这个点继续往下搜索,同理还会继续回到该点(vi),于是这个环加上上次那个环就构成了一个更大的环,即可以想象成形成了一条从 v0 到 vi的路径,再由 vi 走了一个环回到 vi,然后到达v0 的一条更长的路径,如果当前的路径还不是最长的,那么继续按照上面的方法扩展。只需要在回溯时记录下每次回溯的边,最后形成的边的序列就是一条欧拉回路。如果要记录点的顺序的话,那么每访问一个点,就把这个点压入栈中,当某个点不能继续搜索时,即在标记不能走的边是,这个点成为了某种意义上的孤点,然后把这个点输出最后得到的就是一条欧拉回路路径的点的轨迹。

  总之,求欧拉回路的方法是,使用深度优先搜索,如果某条边被搜索到,则标记这条边为已选择,并且即使回溯也不能将当前边的状态改回未选择,每次回溯时,记录回溯路径。深度优先搜索结束后,记录的路径就是欧拉回路。

下面用图描述一遍:

假设我们选择从v1开始走,由于随便走,所以可能出现以下走法

第一步:v1 -- v9

第二步:v9 -- v8

第三步:v8 -- v10

第四步:v10 -- v1

此时由于走过的边不能再走,那么从 v1 就无法继续向下探索,所以往前回溯,记录边集Eu{<v1, v10>},此时回溯到 v10 ,发现可以继续走,那么

第五步: v10 -- v3

第六步: v3 -- v2

第七步: v2 -- v4

第八步: v4 – v10

发现已经无路可走,那么继续回溯,记录回溯路径得到Eu{<v1,v10>, <v10, v4>, <v4, v2>, <v2, v3>, <v3, v10>, <v10, v8>},此时回溯到了 v8.发现可以向其他方向搜索, 那么

第九步:v8 -- v6

第十步:v6 --v7

第十一步:v7-- v8

又无路可走,继续回溯Eu{<v1,v10>, <v10, v4>, <v4, v2>, <v2, v3>, <v3, v10>, <v10, v8>, <v8, v7>, <v7, v6>,<v6,v8>,<v8,v9>,<v9,v1>},到这里整个DFS就结束了,我们得到的边集Eu就是一条欧拉回路。

摘毕。。。。。。。。。。。。。。。。。。。。。。。。。。。。。

这里小bi一句:其实很多算法只要你愿意花时间去模拟一遍,就能理解了

下面开始讲题:

传送门

这次我们先看一下代码,毕竟就只是一个裸的欧拉回路模板题,没什么好分析的,代码中会解释一些骚操作

代码:

#include<cstdio>
#include<cmath>
#include<cstring>
#include<algorithm>
#include<iostream>
#include<cstdlib>
#include<vector>
#define M 400009
#define N 100009
#define inr read()
using namespace std;
int type,n,m;
int nxt[M],head[N],to[M],cnt=1;
int in[N],out[N];
bool vis[M];
vector<int> ans;
void add(int x,int y){  nxt[++cnt]=head[x];head[x]=cnt;to[cnt]=y; }
inline int read(){char ch;int f=1,res=0;while((ch=getchar())<'0'||ch>'9')if(ch=='-') f=-1;while(ch>='0'&&ch<='9'){res=(res<<1)+(res<<3)+ch-'0';ch=getchar();}return f==1?res:-res;
}
void dfs(int u){for(int &e=head[u];e;e=nxt[e]){//当前弧优化(学过网络流的就明白,没学过的。。自己查吧)int v=to[e],c=(type==1?(e/2):(e-1));//后面单独讲一下int sign=e&1;if(vis[c]) continue;vis[c]=1;dfs(v);if(type==1) ans.push_back(sign==1?-c:c);else ans.push_back(c);}
}
int main(){type=inr;n=inr;m=inr;int i,j,k;for(i=1;i<=m;++i){int u,v;u=inr;v=inr;add(u,v);out[u]++;in[v]++;//记录出度和入度if(type==1) add(v,u);}if(type==1){for(i=1;i<=n;++i)if((in[i]+out[i])&1){ // x&1,是判断 x 的奇偶,x&1==1,则说明x为奇数printf("NO");return 0;} }else{for(i=1;i<=n;++i)if(in[i]!=out[i]){//有向图:出度不等于入度printf("NO");return 0;}}for(i=1;i<=n;++i)if(head[i])//要排除孤立点,找到第一个不是孤立点的点{dfs(i);break;}if(ans.size()!=m) {printf("NO");return 0;}//如果刚刚找到的欧拉回路并没有包含所有的边,//那么说明刚刚找到的只是图中的一个子图,说明整个图除了孤立点以外仍旧不连通那么肯定不是欧拉图printf("YES\n");for(i=m-1;i>=0;--i)//倒着输出,如果明白了之前模拟的算法过程就知道为什么了printf("%d ",ans[i]);return 0;
}

来单独讲一下这一步:c=(type==1?(e/2):(e-1));
之所以可以这样处理是因为我们是从2开始存的边

那么如果是从1开始存边就应该这样写:c=(type==1?(e%2==0?e/2:(e+1)/2):e)

是不是好写的多?

这个 c 表示的就是这条边本来的编号,你想咯,无向边存了两遍,但实际上还是指的同一条边,可以举几个例子自己看看

0816-欧拉回路(外带模板题一个+sao操作)相关推荐

  1. 哥尼斯堡的“七桥问题” (25 分)【欧拉回路模板题】

    立志用最少的代码做最高效的表达 哥尼斯堡是位于普累格河上的一座城市,它包含两个岛屿及连接它们的七座桥,如下图所示. 可否走过这样的七座桥,而且每桥只走过一次?瑞士数学家欧拉(Leonhard Eule ...

  2. 牛客 - 小A的回文串(Manacher模板题)

    题目链接:点击查看 题目大意:给出一个字符串s,现在可以对字符串进行一次操作,具体规则是可以将字符串的一个前缀在不改变顺序的情况下变为其后缀,问如何操作可以使得最长回文子串的长度尽可能长,题目要求输出 ...

  3. P2163 [SHOI2007]园丁的烦恼(二维数点模板题)

    P2163 [SHOI2007]园丁的烦恼 题意: 在一个二维平面内有一些点,给你一个左上角和右下角的点,问这个范围内有多少点 题解: 二维数点模板题 我们设F(a,b)表示以(0,0)为左下角,(a ...

  4. 树的同构模板题(法1.最小表示法+法2.树哈希)

    树的同构 problem solution code solution code problem 模板题 solution Ⅰ. 最小表示法 将树转化为 0/10/10/1 括号序列:从根开始 dfs ...

  5. BZOJ 3223: Tyvj 1729 文艺平衡树-Splay树(区间翻转)模板题

    3223: Tyvj 1729 文艺平衡树 Time Limit: 10 Sec  Memory Limit: 128 MB Submit: 6881  Solved: 4213 [Submit][S ...

  6. 【BZOJ - 3224】普通平衡树(Splay模板题)

    题干: 您需要写一种数据结构(可参考题目标题),来维护一些数,其中需要提供以下操作: 1. 插入x数 2. 删除x数(若有多个相同的数,因只删除一个) 3. 查询x数的排名(若有多个相同的数,因输出最 ...

  7. ~~一般哈希(数据结构)(附模板题AcWing 840 模拟散列表)

    (1) 拉链法 int h[N], e[N], ne[N], idx;// 向哈希表中插入一个数 void insert(int x) {int k = (x % N + N) % N;e[idx] ...

  8. ~~堆(数据结构)(附模板题 AcWing 838. 堆排序)

    模板 // h[N]存储堆中的值, h[1]是堆顶,x的左儿子是2x, 右儿子是2x + 1 // ph[k]存储第k个插入的点在堆中的位置 // hp[k]存储堆中下标是k的点是第几个插入的 int ...

  9. ~~队列(数据结构)(附模板题 AcWing 829. 模拟队列)

    1. 普通队列: // hh 表示队头,tt表示队尾 int q[N], hh = 0, tt = -1;// 向队尾插入一个数 q[ ++ tt] = x;// 从队头弹出一个数 hh ++ ;// ...

最新文章

  1. 超强实时人像抠图算法开源,随心所欲背景替换!
  2. vsCode 开发微信小程序插件
  3. oracle动态性能视图和静态,oracle最重要的9个动态性能视图
  4. Vim 4 常用插件
  5. 细数Android开发者的艰辛历程,已拿offer附真题解析
  6. mysql kill 超过1分钟的语句
  7. 查看SQL Server当前会话的隔离级别
  8. 安装pycrypto 2.6.1各种坑
  9. oracle导致的负载高,oracle服务器负载过高_停止RMAN备份任务
  10. pyqt5 列表内添加按钮
  11. 百度App网络深度优化系列(一):DNS优化
  12. SDWebImage 笔记
  13. caffe常用小工具
  14. 社交系统中用户好友关系数据库设计
  15. vscode vue开发环境搭建
  16. app架构师实践指南pdf,分享一些行业经验,看完这一篇你就懂了
  17. Expandable TabBar
  18. python海龟画五角星随机_Python turtle 绘制五角星
  19. Free Download Manager
  20. 什么是胖客户端和瘦客户端?什么是哑终端?(转)

热门文章

  1. 动物代谢成像(SPECT/PET)放射性同位素标记实验/18f/99mtc/125l/68Ga放射性标记
  2. 5G时代的新商业版图
  3. 【Bug】一次Android系统应用32位升级到64位的踩坑记录
  4. 【北亚数据恢复】通过碎片拼接技术恢复XenServer服务器磁盘中SQL Server数据库数据
  5. [Python]Tkinter-GUI二维码生成器
  6. Ubuntu虚拟机使用花生壳内网击穿后外网登录自己写的web服务器
  7. Vue warn]: Error compiling template:
  8. web使用window.print()实现分页批量打印。
  9. C21-RK2106美的电磁炉出现间歇加热故障
  10. 前向渲染和延迟渲染基本概念