1、基本概念:
(1)定义
欧拉通路(欧拉迹)—通过图中每条边一次且仅一次,并且过每一顶点的通路。
欧拉回路(欧拉闭迹)—通过图中每条边一次且仅一次,并且过每一顶点的回路。
欧拉图—存在欧拉回路的图。欧拉图就是从一顶出发每条边恰通过一次又能回到出发顶点的那种图,即不重复的行遍所有的边再回到出发点。
通路和回路-称vie1e2…envj为一条从vi到vj且长度为n的通路,其中长度是指通路中边的条数.称起点和终点相同的通路为一条回路。
简单图-不含平行边和自回路的图。
混合图-既有有向边,也有无向边的图
平凡图-仅有一个结点的图
完全图-有n个结点的且每对结点都有边相连的无向简单图,称为无向完全图;有n个结点的且每对结点之间都有两条方向相反的边相连的有向简单图为有向完全图。
(2)欧拉图的特征:
无向图
a)G有欧拉通路的充分必要条件为:G连通,G中只有两个奇度顶点(它们分别是欧拉通路的两个端点)。
b)G有欧拉回路(G为欧拉图):G连通,G中均为偶度顶点。
有向图
a)D有欧拉通路:D连通,除两个顶点外,其余顶点的入度均等于出度,这两个特殊的顶点中,一个顶点的入度比出度大1,另一个顶点的入度比出度小1。
b)D有欧拉回路(D为欧拉图):D连通,D中所有顶点的入度等于出度。一个有向图是欧拉图,当且仅当该图所有顶点度数都是0。
2、例题
混合图,有向边和无向边,如何将一些无向边调整为有向后满足欧拉回路的要求,设点有向边入度为in[i],出度为out[i],无向边度为deg[i],如果di=in[i]+out[i]+deg[i]为奇数或者in[i]>di/2,或者out[i]>di/2,则无解,剩下的问题便是如何对每个点i通过调节无向边使得in[i]==di/2便可以了(out[i]也肯定是剩下的di/2,即in[i]==out[i]),一条无向边连接两个顶点v,u,无向边改向后,两点中只有一个得到这条边,类似前面讲的打比赛模型中的两个人抢一场比赛问题,其实解法就是一样的!设超级源source引边到每个点 ,容量为di/2-in[i] 表示这个点还要得到这么多条有向边才能满足最后欧拉路的要求, 对每条边引一个容量为1的边到超级汇sink,从它相关的两个顶点分别引一条边过来,容量为1,做一次最大流后,检查source出的的每条边是否都流尽,流尽说明每个点都达到将入度调为di/2的目的!否则无解,此题也可以同样的方法将n+m个点优化为n个点,详见前面。
要求每条边恰好经过两次,且两次经过的方向不同,将每条边拆成两条有向边,则问题转化为有向图的欧拉回路,输出path[]则为解
voidEuler(int v,int& step,int* path){
int i;
for(int i=p[v];i!=-1;i=edge[i].pre){
if(edge[i].w){
edge[i].w=0;
Euler(n, edge[i].d, step, path);
}
}
path[step++]= now; //注意path[]放的位置,不能乱放,^_^...否则先记录后面的点再加来记录中间的,
}
每条边有标号,要求一条欧拉路径,输出边序字典序最小,有一个O(e*e)的算法,就是每层都在e条边中从小到大找出与当前点相关的边的端点进行下一次DFS,这一步是O(e),本题e<=1995,可以接受,其实仔细观察一下前向星存边时的顺序,可以发现完全可以降为O(e)的,首先按边的id从大到小sort一下,在插入边的时候,前向星里自动把同一个顶点出发的多条边按id从小到大排序好了,因为前向星的顺序刚好是相反,所以DFS时每次都会先从id小的边出发!从而避免每次都要去e条边里找出跟目前点相关的点。
每个单词用且用一次,跟欧拉图的边经过且经过一次一样,于是将26个字母视为点,单词视为边,每个单词第一个字母引有向边到最后一个字母,如果图中存在欧拉通路或者欧拉回路,则说明有解,否则无解,有一个trick是,图有可能还不连通,所以删边后要判断每条边是不是都删掉了,即都经过一次。
这个题是1386和1041的结合版 ,用1386的方法构图,用1041的方法将O(e*e)降为O(e),可惜的是e<=1000,体现不出什么优势,甚至和别人的O(n*n)速度一样,冏...
hdu 3472如果图不连通,无解,如果奇度数点的个数大于2,无解,若恰好为两个,则在它们之间连一条无向边,问题转化为上面的pku1637求欧拉回路,若无奇度点,则直接求欧拉回路。