首页 > 代码库 > 欧拉回路

欧拉回路

//这是贴的;

欧拉回路:图G,若存在一条路,经过G中每条边有且仅有一次,称这条路为欧拉路,如果存在一条回路经过G每条边有且仅有一次,

称这条回路为欧拉回路。具有欧拉回路的图成为欧拉图。

判断欧拉路是否存在的方法

有向图:图连通,有一个顶点出度大入度1,有一个顶点入度大出度1,其余都是出度=入度。

无向图:图连通,只有两个顶点是奇数度,其余都是偶数度的。

判断欧拉回路是否存在的方法

有向图:图连通,所有的顶点出度=入度。

无向图:图连通,所有顶点都是偶数度。

如下是判断欧拉回路是否存在的代码:

 

#include <cstdio>
#include <cstring>

 

int set[1000 +10] , p[1000 +10];

 

int find(int x){
return set[x] == -1 ? x : find(set[x]);
}

 

int main(){
int n , i , j , m;
while(scanf("%d",&n),n){
scanf("%d",&m);
memset(p,0,sizeof p);
for(i = 1 ; i <= n ; i ++)set[i] = -1;
while(m--){
int a,b,x,y;
scanf("%d%d",&a,&b);
x = find(a);
y = find(b);
if(x != y)set[a] = b;
p[a]++;p[b]++;
}
int Q=0;
for(i = 1; i <= n ; i ++){
if(set[i] == -1)Q++;
if(p[i]%2)Q++;
}
if(Q>1)puts("0");
else puts("1");
}
}

 

程序实现一般是如下过程:

1.利用并查集判断图是否连通,即判断p[i] < 0的个数,如果大于1,说明不连通。

2.根据出度入度个数,判断是否满足要求。

3.利用dfs输出路径。

比较好的题目是poj2337,判断单词是否连成一排的。

hdu3018

给出N个节点,M个边,问要遍历一遍所有的边,需要的最小group数目。
求一个图中最少几笔画,利用欧拉回路性质,首先得到图的每个强连通分支,然后计算每个强连通分支每个是否都是偶数度是的话,一笔解决,否的话,需要奇数度节点个数的1/2笔解决。(当一个节点度数为奇数时,我们只需要令它的度数为1,因为偶数的话直接抵消了,最后判断一个scc中未1的节点个数,除以2就得到该scc的最小笔画了)

poj1386

给出n个单词,如果一个单词的尾和另一个单词的头字符相等,那么可以相连,问这n个单词是否可以排成一列。欧拉路应用,构图:一个单词的头尾字母分别作为顶点,每输入一个word,该word的头指向word的尾画一个有向边,并且记录每个顶点的出入度。利用并查集先判断是否为scc,如果是的话则判断是否奇数度节点为0或者只有2个。

poj2230

题目大意:给出n个field及m个连接field的边,然后要求遍历每条边仅且2次,求出一条路径来。
这个题目典型欧拉回路,由于题目保证了肯定存在,所以我们直接dfs就行,首先有个小技巧是如何判断该条路是否走过了,也就是我们得对有向边进行标记。利用之前的结构
struct edge{
    int next;
    int to;
};
edge node[maxm];
int adj[maxv] = {-1}
每一条边对应了一个next,我们只需要对next标记就可以了。

poj2337
求欧拉路径和poj1386同一个题,只不过这个题目需要输出欧拉路径。
题目大意:给出一组单词,如果两个单词,一个单词的头和另一个单词的尾相同,则可以相连,例如abce, efdg,可以相连,问这组单词能否排成一排,如果可以求出字典序自小的那个。
构图:单词作为边,单词的头字母和尾字母分别作为顶点,读入一个单词,添加一条边,并且用邻接表来存边,首先利用并查集判断图是否连通,然后再判断是否可以构成欧拉通路或者回路,如果是回路,则从a开始找,找到第一个存在的字母,从这个字母遍历就行,如果是通路,则必须从出度大于入度1的那个顶点开始遍历。由于这个题目要求最小字典顺序,然后考虑我们建立邻接表的时候是采用头插法,那么我们如果将单词从小到大排序,由于我们遍历顶点肯定是从小的顶点开始的,这样遍历一个顶点的邻接边的时候就会从大到小访问这个顶点的边,无法满足字典最小,所以从大到小排序,遍历依node数组为准,每次遍历一条边设置该下标已访问过。