欧拉回路设计报告
if(d[i]%2!=0)y++;
} 1.23、欧拉回路的判断
判断欧拉回路时根据欧拉定理进行判断,首先要判断是否为连通图,不是连通图就不进 行后面的判断。如果时连通图且图中 M 个顶点的度都为偶数则存在欧拉回路,因此,欧拉 图一笔画的判定与求解就是对输入的无向连通图是度的判定。当连通图中所有顶点的度都为 偶数时,连通图就存在欧拉回路。
scanf("%d",&node[i]);scanf("%d",&node[i+1]); node[i+2]=node[i+1];node[i+3]=node[i]; x=node[i]; d[x]++; x=node[i+1]; d[x]++; i=i+4; } for(i=1;i<=M;i++)//结点度的判断 { if(d[i]%2!=0)y++; } for(i=1;i<=M;i++) { vertex_node[i].vertex=i; vertex_node[i].flag=0; vertex_node[i].nextnode=NULL; } creat_graph(node,2*N); if(dfs(1)<M||(y!=0)) {tu[a]=0;}
连通图采用邻接表存储,,并且输入顶点信息。 输入的数据为无向图的顶点数和边数,顶点数为大于 0 小于 1000 的整数,边数为非负 的整数,还有邻接表中结点的值(起点和终点),都为非负整数。 输入的无向图,可为连通也可不连通,也可输入单个顶点的图,程序会进行判断。 1.2、算法描述 1.2.1、无向图的存储结构和连通图的判定 采用邻接表存储无向图,利用 graph 表示邻接表用来存储无向图,输入结点数 M 和边 数 N,还有邻接表的值(起点和终点),即边的信息。 图的连通性的判断,用到图的深度优先搜索,采用深度优先搜索来遍历无向图中的点的 信息,从图中某个顶点出发首先访问该顶点,然后任选一个该点未访问的邻接点出发,直到 访问完成。计算出深度优先搜索到点的数目,然后与结点数进行比较,如果遍历到的数目小 于结点数,则为非连通图,否则,为连通图。 1.22、无向图结点度的求法 在无向图建立时求图结点的度,当输入结点信息时用数组 d[i]来存储各节点的度然后判 断度得奇偶性 for(i=1;i<=M;i++)//结点度的判断
开始
输入节点数为 0 N
建立无向图的邻接表
N 是连通图
Y Y
N 顶点度都为偶
数 Y
欧拉回路
不是欧拉图
结束
2、main(主函数) 1.4 creat_graph(邻接矩表建立函数)
功能:根据输入的顶点数和边数还有邻接表的值建立无向图的邻接表。 参数含义:数组 vertex_node 为结构体变量,graph 为结构体类型,数组 node[i]存储结 点。 简单的工作过程:从键盘输入顶点数和边数,邻接表的值(起点和终点);初始化邻接
p=p->nextnode; p->nextnode=newnode; } } 无向图的深度优先搜索,其中 s 是返回搜索道边的数目。定义指针 p,用 flag 标志结点 是都被访问过。S 用来记录访问过的结点的数目。 int dfs(int k) { graph p; vertex_node[k].flag=1; printf("vertex[%d]",k); s++;
利用深度优先遍历的基本操作来实现的欧拉算法求解欧拉回路。算法就是深度优先遍历 连通图,然后求出连通图中各结点的度。 四、系统设计 1.1 设计说明
该程序设计共包括四大模块:主函数模块,邻接表建立模块,连通图判定模块,欧拉回
路求解模块。主函数中调用了其他所有三个模块,连通图的判定模块与欧拉回路解模块都调 用了邻接表建立模块中建立的邻接表,主函数中包含了结点度的计算,以及欧拉回路判断的 输出。函数模块关系如图 1 所示:
欧拉回路的判定
主函数模 块
邻接表建立模 块
连通图判 定模块
(主函数中) 欧拉回路判 断和输出
1、函数模块关系图 1.2 数据结构描述
该程序主要用到图等数据结构,它们的表示和实现如下所示: 图的存储,用的是连接表存储。定义邻接表的结点和指针,数组 node[i]用来存储结点 信息。通过输入边的信息,用邻接表对无向图进行存储。 void creat_graph(int *node,int n) {graph newnode,p;
附 录(程序清单)
#include<stdio.h> #include<stdlib.h> int s=0; struct node { int vertex;
int flag; struct node *nextnode; }; typedef struct node *graph;//结点类型 struct node vertex_node[10]; void creat_graph(int *node,int n)//图的存储 { graph newnode,p;//定义一个新节点及指针 int x,y,i; for(i=0;i<n;i++) { x=node[i*2];//边的起点
p=p->nextnode;//寻找链尾 p->nextnode=newnode;//在链尾处插入新节点 } } int dfs(int k)//连通图判定 { graph p; vertex_node[k].flag=1;//将标志位置 1,证明该节点访问过 s++;
p=vertex_node[k].nextnode;//指针指向下一节点 while(p!=NULL) { if(vertex_node[p->vertex].flag==0)//判断该节点的标志位是否为零
int start,end,i; for(i=0;i<n;i++) { start=node[i*2];
end=node[i*2+1]; newnode=(graph)malloc(sizeof(struct node)); newnode->vertex=end; newnode->nextnode=NULL; p=&(vertex_node[start]); while(p->nextnode!=NULL)
3、输出结果 输入验证单结点的无向图和多结点无向图,以及偶来图和非欧拉图。 程序对测试输入为: 43 121323 输出结果如下图 4:
4、输出结果 输入验证输入无向图为非连通图图,用来判断无向图是否为欧拉图。 程序对测试输入为: 一组:3 3 1 2 1 3 2 3 二组:3 2 1 2 2 3 输出结果如下图 5:
dfs(p->vertex);//继续遍历下一节点 p=p->nextnode; }return s;//返回访问节点数目 } void main() { int node[100],i,a=-1,x,y=0,d[100],N,M; int tu[10];
printf("\t*************************** 欧 拉 回 路 的 判 断 ***************************\t\n");
表;根据输入的起点和终点用 node[i]存储结点信息;这样邻接表就建立完成。 1.5dfs(连通图判定函数)
功能:判断输入的无向图是否为连通图。 参数含义:graph p 为之前建立好的无向图的邻接表。 简单的工作过程:图的深度优先的过程,用到图的深度优先搜索,采用深度优先搜索来 遍历无向图中的点的信息,从图中某个定点出发首先访问该顶点,然后任选一个该点未被访 问的邻接点出发,直到访问完成。计算出深度优先搜索到点的数目,然后与结点数进行比较, 如果遍历到的数目小于结点数,则为非连通图,否则,为连通图。 1.6 欧拉回路求解 功能:求解连通图的欧拉回路并输出。 此过程是在主函数中实现的。简单的工作过程:有欧拉图的定义来判断。如果一个无相 连通图中各结点的度均为偶数,则是偶来回路。根据函数是否为连通图以及各结点的度,来 判断无向图是否存在欧拉回路。若是输出 yes,否则输出 no。 五、测试结果及其分析 程序的测试结果和输出为: 输入为: 一组:1 0 二组:3 2 1 2 1 3 三组:3 3 1 2 1 3 2 3 输出结果如下图 3:
y=node[i*2+1];//边的终点 newnode=(graph)malloc(sizeof(struct node)); newnode->vertex=y;//新节点的内容为边终点处顶点的内容 newnode->nextnode=NULL; p=&(vertex_node[x]);//设置指针位置 while(p->nextnode!=NULL)
while(12){s=0; a++;y=0; for(i=0;i<100;i++) d[i]=0;
printf("输入结点数和边数:"); scanf("%d",&M); if(M==0)break;scanf("%d",&N); if(N!=0) printf("输入边信息:\n"); for(i=0;i<4*N;)//将节点信息存入数组中 {
合肥学院 计算机科学与技术系
课程设计报告
2012 ~2013 学年第 二 学期
课
程
课程设计名称
学生姓名
学
号
专业班级
指导教师
数据结构与算 欧拉回路
计算机科学与技术系 11 级 4 班
2013 年 3 月
欧拉图及哈密顿图
充分性:设连通图G恰有两个奇数度结点, 不妨设为a和b,在图G中添加一条边e={a,b} 得G’,则G’的每个结点的度数均为偶数,因 而G’中存在欧拉回路,故G中必存在欧拉路.
定义2 给定有向图D,经过D中每边一次且仅 一次的有向迹称为D的有向欧拉路.经过D中 每边一次且仅一次的有向闭迹(回),称为有 向欧拉回路.
哈密顿图 定义3 具有哈密顿回路的无向图与具有哈密顿有 向回路的有向图,统称为哈密顿图. 例1对于完全图Kn(n3),由于Kn中任意两个顶点之 间都有边,从Kn的某一顶点开始,总可以遍历其余 节点后,再回到该结点,因而Kn(n3)是哈密顿图.
说明:判断一个给定的图是否为哈密顿图,是图论 中尚未解决的难题之一,下面介绍若干必要条件 和充分条件.
(3)检查G2的每个圈C,若某个圈C上重复边集E 的权和超过这个圈的权和的一半,则将C按定理1 必要性证明中的方法进行调整,直到对G2所有的 圈其重复边的权和不超过此圈权和的一半,得到 图G3. (4)用Fleury算法求G的Euler回路.
例3 求下图G的最优环游.
v1 5 v2 5 v3 9 v4 A 6 v11 4 3 v5
求Euler图的Euler回路的Fleury算法. (1)任意选取一个顶点v0,置W0=v0; (2)假定迹(若是有向图,则是有迹) Wi=v0e1v1…eivi已经选出,则 用下列方法从E(G)-{e1,e2,…,ei}中取ei+1; (a)ei+1与vi关联(若是有向图, ei+1 以vi为起点) (b)除非没有别的边可选择, ei+1不是 Gi=G- {e1,e2,…,ei}的割边. (3)当(2)不能执行时,停止.否则让i+1 i,转 (2).
哈密顿图
欧拉回路的算法演示
欧拉图中欧拉回路的算法,演示,及分析
设G为欧拉图,一般来说G中存在若干条欧拉回路,下面介绍两种求欧拉回路的算法。
1.Fleury算法,能不走桥就不走桥:
(1)任取v0∈V(G),令P0=v0.
(2)设Pi=v0e1v1e2…e i v i已经行遍,按下面方法来从E(G)-{e1,e2,…,e i}中选取e i+1:
(a)e i+1与v i相关联;
(b)除非无别的边可供行遍,否则e i+1不应该为G i=G-{e1,e2,…,e i}中的桥。
(3)当(2)不能再进行时,算法停止。
可以证明,当算法停止时所得简单回路P m=v0e1v1e2…e m v m(v m=v0)为G中一条欧拉回路。
例15.2 图15.4(1)是给定的欧拉图G。
某人用Fleury算法求G中的欧拉回路时,走了简单回路v2e2v3e3v4e14v9e10v2e1v1e8v8e9v2之后(观看他的错误走法),无法行遍了,试分析在哪步他犯了错误?
解此人行遍v8时犯了能不走桥就不走桥的错误,因而他没行遍出欧拉回路。
当他走到v8时,G-{e2,e3,e14,e10,e1,e8}为图15.4(2)所示。
此时e9为该图中的桥,而e7,e11均不是桥,他不应该走e9,而应该走e7或e11,他没有走,所以犯了错误。
注意,此人在行遍中,在v3遇到过桥e3,v1处遇到过桥e8,但当时除桥外他无别的边可走,所以当时均走了桥,这是不会犯错误的。
欧拉路径和欧拉回路
来自USACO上的例子 来自USACO上的例子 USACO
Stack: 1 4 2 5 Location: 6 Circuit: 1 5 7 6 4 3 7 2
来自USACO上的例子 来自USACO上的例子 USACO
Stack: 1 4 2 Location: 5 Circuit: 1 5 7 6 4 3 7 2 6
Q&A
混合图
混合图的定义: 有的边是有向的,有的边是无向的。例如城市 里的交通网络,有的路是单行道,有的路是双 行道。 找到一个给每条无向的边定向的策略,使得每 个顶点的入度等于出度,这样就能转换成上面 第二种情况。
关于欧拉路径
源点与汇点不为同一点. 判定一个图是否有欧拉路径. 一个无向图中除源点与汇点的度数为奇数 外,其于点的度数都为偶数,那么则存在欧拉 路径.
伪代码
find_circuit(node i) { 如果当前结点没有边 将其加入到路径中 否则:while(node i 没有相连的边) { j是与i相临的顶点(即i,j之间有一条边) find_circuit(j); 删除i和j之间的边 } 将i加入路径中去 }
void solve(int x) { if(match[x] == 0) { Record[RecordPos] = x; RecordPos++; }
无向图
每个顶点的入度是偶数,则存在欧拉回路. 证明很简单:其原理就是每个顶点要进去多少 次,就必须出来多少次.如果存在度为奇数的 顶点,那么必有通过某一边进入这一点后,没 有边可以出去,这样就不会有回路.
有向图
每个顶点的入度和出度相等. 原理同无向图.也是有多少边进入,就要有多 少边出去. 对于混合图这里就不祥细说明了.
欧拉回路解题实例分
题目意思:给你一个n,让你找到一个2^n的0、1串,使每循环移动一位,表示不同的数。
总共可以表示0---2^n-1中的每一个数。
解题思路:以0--2^(n-1)-1为编号建立一棵树,共2^(n-1)个节点,如果在某个节点后面添加一个0或者1,再去掉最高位,得到下一个节点,两节点之间连一条有向边。
图中每条边就表示了一个数,共有2^n个数,各不相同。
题目要求字典序最小,则从2^(n-1-1节点开始,并且每个节点先连加0的边,后连加1的边,这样的话,就能保证最终的字典序最小。
代码:[cpp]<SPAN style="FONT-SIZE: 18px">#include<iostream>#include<cmath>#include<cstdio>#include<cstdlib>#include<string>#include<cstring>#include<algorithm>#include<vector>#include<map>#include<stack>#include<list>#include<queue>#define eps 1e-6#define INF (1《30)#define PI acos(-1.0)using namespace std;struct Inf //表示一条边,序号表示边起始点,v表示终点,via表示连0还是1,vis表示该边是否访问{int v,via;bool vis;};vector<Inf>myv[17000]; //2^14=16384char path[33000]; //共可以表示2^n个数,2^15=32768int n,cnt;void init() //初始化向量容器{for(int i=0;i<=n;i++)myv[i].clear();return ;}void dfs(int cur){for(int i=0;i<myv[cur].size();i++){if(myv[cur][i].vis==false){myv[cur][i].vis=true;dfs(myv[cur][i].v);path[++cnt]=myv[cur][i].via+'0';//保存边,最先进来的是最后的边,用栈保存}}return ;}int main(){int k;while(scanf("%d%d",&n,&k)!=EOF){if(n+k==0)break;int lan=n;n=(1《(n-1))-1; //最大的节点标号init();struct Inf temp;for(int i=0;i<=n;i++){int tt=(i《1)-((i&(1《(lan-2)))《1);//在后面添0并去掉最高位//printf("i:%d %d\n",i,tt);temp.v=tt;temp.via=0;temp.vis=false;myv[i].push_back(temp);tt+=1; //在后面添1并去掉最高位temp.v=tt;temp.via=1;myv[i].push_back(temp);}cnt=-1;dfs(n);path[++cnt]='\0';std:reverse(path,path+cnt);//倒过来//printf("%s\n",path);int ans=0;for(int i=k,j=1;j<=lan;j++,i++) //输出旋转k个位置后表示的数,注意是n位ans=(ans《1)+path[i%cnt]-'0';printf("%d\n",ans);}return 0;}</SPAN>#include<iostream>#include<cmath>#include<cstdio>#include<cstdlib>#include<string>#include<cstring>#include<algorithm>#include<vector>#include<map>#include<stack>#include<list>#include<queue>#define eps 1e-6#define INF (1《30)#define PI acos(-1.0)using namespace std;struct Inf //表示一条边,序号表示边起始点,v表示终点,via表示连0还是1,vis表示该边是否访问{int v,via;bool vis;};vector<Inf>myv[17000]; //2^14=16384char path[33000]; //共可以表示2^n个数,2^15=32768int n,cnt;void init() //初始化向量容器{for(int i=0;i<=n;i++)myv[i].clear();return ;}void dfs(int cur){for(int i=0;i<myv[cur].size();i++){if(myv[cur][i].vis==false){myv[cur][i].vis=true;dfs(myv[cur][i].v);path[++cnt]=myv[cur][i].via+'0';//保存边,最先进来的是最后的边,用栈保存}}return ;}int main(){int k;while(scanf("%d%d",&n,&k)!=EOF){if(n+k==0)break;int lan=n;n=(1《(n-1))-1; //最大的节点标号init();struct Inf temp;for(int i=0;i<=n;i++){int tt=(i《1)-((i&(1《(lan-2)))《1);//在后面添0并去掉最高位//printf("i:%d %d\n",i,tt);temp.v=tt;temp.via=0;temp.vis=false;myv[i].push_back(temp);tt+=1; //在后面添1并去掉最高位temp.v=tt;temp.via=1;myv[i].push_back(temp);}cnt=-1;dfs(n);path[++cnt]='\0';std:reverse(path,path+cnt);//倒过来//printf("%s\n",path);int ans=0;for(int i=k,j=1;j<=lan;j++,i++) //输出旋转k个位置后表示的数,注意是n位ans=(ans《1)+path[i%cnt]-'0';printf("%d\n",ans); }return 0;}。
欧拉回路构造算法
欧拉回路构造算法全文共四篇示例,供读者参考第一篇示例:欧拉回路是图论中的一个重要概念,在一幅图中指的是一条包含图中每一条边且经过每一条边仅一次的闭合路径。
欧拉回路构造算法是指寻找一条欧拉回路的方法,即将给定的图转化为满足欧拉回路性质的路径。
欧拉回路构造算法有多种,其中最为经典和常用的算法是Fleury 算法和Hierholzer算法。
Fleury算法是一种基于贪心思想的算法,其基本思路是每次选择一条不是桥的边,通过DFS搜索来构造欧拉回路。
具体步骤如下:1. 从图中任选一个顶点作为起点。
2. 找到可以走的一条不是桥的边,并走向该边所连接的顶点。
3. 如果该边是割边,则在走完该边后,必须选择一条不是割边的边继续前进。
4. 重复步骤2和步骤3,直到不能走为止。
Fleury算法的时间复杂度为O(E^2),其中E为图中的边数。
Hierholzer算法是另一种求解欧拉回路的经典算法,其基本思想是通过遍历所有的边来构造欧拉回路。
具体步骤如下:1. 从图中任意一个顶点开始,选择一条边进行遍历。
2. 如果走到某个节点时无法继续行走,则回退到之前分叉点重新选择一条边继续遍历。
3. 直到遍历完所有的边,形成一个闭合回路即为欧拉回路。
欧拉回路构造算法的应用十分广泛,例如在网络设计、图像处理、数据压缩等领域都有着重要的作用。
通过欧拉回路构造算法,我们可以快速有效地找到一条经过所有边的闭合路径,从而解决一系列实际问题。
欧拉回路构造算法是解决图论中欧拉回路问题的重要工具。
不同的算法适用于不同的情况,可以根据具体问题的要求选择合适的算法。
通过学习和了解欧拉回路构造算法,我们可以更好地运用图论知识解决实际问题,提高问题解决的效率和准确性。
希望本文对读者有所帮助,欢迎大家进一步深入学习和探讨。
第二篇示例:欧拉回路构造算法是图论中一种重要的算法,用于寻找图中存在的欧拉回路。
欧拉回路是指一条包含所有边且不重复经过任何边的闭合路径。
在很多实际应用中,欧拉回路是一个非常有用的概念,比如在电子电路的布线设计、网络路由、以及城市旅行等领域都有很多应用。
欧拉回路
Eulerian Tour欧拉路径译 by 孖哥 and tim greenSample Problem: Riding The Fences农民John每年有很多栅栏要修理。
他总是骑着马穿过每一个栅栏并修复它破损的地方。
John是一个与其他农民一样懒的人。
他讨厌骑马,因此从来不两次经过一个一个栅栏。
你必须编一个程序,读入栅栏网络的描述,并计算出一条修栅栏的路径,使每个栅栏都恰好被经过一次。
John能从任何一个顶点(即两个栅栏的交点)开始骑马,在任意一个顶点结束。
每一个栅栏连接两个顶点,顶点用1到500标号(虽然有的农场并没有500个顶点)。
一个顶点上可连接任意多(>=1)个栅栏。
所有栅栏都是连通的(也就是你可以从任意一个栅栏到达另外的所有栅栏)。
你的程序必须输出骑马的路径(用路上依次经过的顶点号码表示)。
我们如果把输出的路径看成是一个500进制的数,那么当存在多组解的情况下,输出500进制表示法中最小的一个 (也就是输出第一个数较小的,如果还有多组解,输出第二个数较小的,等等)。
输入数据保证至少有一个解。
The Abstraction已知:一幅无向图寻找一条只过每边一次的路径.这条路径叫欧拉路径(Eulerian tour).如果此路径和起点和终点是同一点,则此种路径叫欧拉回路.The Algorithm判断一幅图有没有欧拉路径或欧拉回路是很简单,有两个不同的规则可用.∙当且仅当一幅图是相连的(只要你去掉所有度数为0的点)且每个点的度都是偶数,这幅图有欧拉回路.∙当且仅当一幅图是相连的且除两点外所有的点的度都是偶数.∙在第二种情况中,那两个度为奇数的节点一个为起点,剩下的一个是终点.一个解决此类问题基本的想法是从某个节点开始,然后查出一个从这个点出发回到这个点的环路径。
现在,环已经建立,这种方法保证每个点都被遍历.如果有某个点的边没有被遍历就让这个点为起点,这条边为起始边,把它和当前的环衔接上。
欧拉回路
一、欧拉回路所谓欧拉回路与哥尼斯堡7桥问题相联系的.在哥尼斯堡7桥问题中,欧拉证明了不存在这样的回路,使它经过图中每条边且只经过一次又回到起始点.与此相反,设G (V ,E )为一个图,若存在一条回路,使它经过图中每条边且只经过一次又回到起始点,就称这种回路为欧拉回路,并称图G 为欧拉图.在一个图中,连接一个节点的边数称为该节点的度数.对欧拉图,我们有下列结果: 定理1 对连通图G (V ,E ),下列条件是相互等价的: (1)G 是一个欧拉图;(2)G 的每一个节点的度数都是偶数;(3)G 的边集合E 可以分解为若干个回路的并.证明 :()()12⇒ 已知G 为欧拉图,则必存在一个欧拉回路.回路中的节点都是偶度数.()()23⇒ 设G 中每一个节点的度数均为偶数.若能找到一个回路C 1使G=C 1,则结论成立.否则,令G 1=G\C 1,由C 1上每个节点的度数均为偶数,则G 1中的每个节点的度数亦均为偶数.于是在G 1必存在另一个回路C 2.令G 2=G 1\C 2,···.由于G 为有限图,上述过程经过有限步,最后必得一个回路C r 使 G r =G r-1\C r 上各节点的度数均为零,即C r =G r-1.这样就得到G的一个分解 G C C C r =⋅⋅⋅12 .()()31⇒ 设G C C C r =⋅⋅⋅12 ,其中i C (I=1,2,…,r )均为回路.由于G 为连通图,对任意回路i C ,必存在另一个回路j C 与之相连,即i C 与j C 存在共同的节点.现在我们从图G 的任意节点出发,沿着所在的回路走,每走到一个共同的节点处,就转向另一个回路,···,这样一直走下去就可走遍G 的每条边且只走过一次,最后回到原出发节点,即G 为一个欧拉图.利用定理1去判断一个连通图是否为欧拉图比较容易,但要找出欧拉回路,当连通图比较复杂时就不太容易了.下面介绍一种求欧拉回路的算法.二、弗罗莱算法算法步骤如下:(1)任取起始点v v R 00,;→(2)设路)},({,),,({),,({1211201rr i i r i i i v v e v v e v v e R -⋅⋅⋅=已选出,则从E\},,,{21r e e e ⋅⋅⋅中选出边1+r e ,使1+r e 与ri v 相连,除非没有其它选择,G e r r \{}+1仍应为连通的.(3)重复步骤(2),直至不能进行下去为止.定理2 连通的有向图存在欧拉回路的充分必要条件是对任意节点,进入该节点边数(进数)与离开该点的边数(出数)相等.三、中国邮递员问题一名邮递员带着要分发的邮件从邮局出发,经过要分发的每个街道,送完邮件后又返回邮局.如果他必须至少一次走过他管辖范围内的每一条街道,如何选择投递路线,使邮递员走尽可能少的路程.这个问题是由我国数学家管梅谷先生(山东师范大学数学系教授)在1962年首次提出的,因此在国际上称之为中国邮递员问题.用图论的述语,在一个连通的赋权图G (V ,E )中,要寻找一条回路,使该回路包含G 中的每条边至少一次,且该回路的权数最小.也就是说要从包含G 的每条边的回路中找一条权数最小的回路.如果G 是欧拉图,则很容易由弗罗莱算法求出一个欧拉回路,但是若G 不是欧拉图,即存在奇度数的节点,则中国由递员问题的解决要困难得多.本节的主要目标是给出在有奇度数节点的连通图中寻找最小权数的回路的方法.首先注意到,若图G 有奇数度节点,则G 的奇数度节点必是偶数个.把奇数度节点分为若干对,每对节点之间在G 中有相应的最短路,将这些最短路画在一起构成一个附加的边子集E '.令G / =G+E /,即把附加边子集E / 叠加在原图G 上形成一个多重图G /,这时G /中连接两个节点之间的边不止一条.显然G /是一个欧拉图,因而可以求出G /的欧拉回路.该欧拉回路不仅通过原图G 中每条边,同时还通过E / 中的每条边,且均仅一次.邮递员问题的难点在于当G 的奇数度节点较多时,可能有很多种配对方法,应怎样选择配对,能使相应的附加边子集E / 的权数ω(E / )为最小?为此有下列定理.定理 3 设G (V ,E )为一个连通的赋权图,则使附加边子集E / 的权数ω(E / )为最小的充分必要条件是G+E / 中任意边至多重复一次,且G+E / 中的任意回路中重复边的权数之和不大于该回路总权数的一半.证明: 必要性.用反证法.设存在一种奇节点集的配对,使其附加边子集E / 权数 ω(E / )为最小.若 G+E / 中有一条边重复n n ()≥2次,由于G+E /为欧拉图,所以删去相应的二次重复边后仍为欧拉图.这样,相应的附加边子集的权数将减小,这与 ω(E /)为最小的假设矛盾.这说明E /中的边均互不相同.其次,若G+E / 中存在一个回路,使它的重复边的权数之和大于该回路总权数的一半,则在E / 中删去这些重复边(注意:这些边均在E /中),而代之以该回路的其余部分的边再重复一次.经过这种替代后所得到的边子集E //仍为附加子集,且ω(E //)<ω(E /),又产生矛盾. 充分性.设有两个附加边子集E /和E //,均使G+E /和G+E //中每条边至多重复一次,且每个回路中的重复边的权数和不大该回路权数的一半,我们来证明ω(E /)=ω(E //).首先注意到,由E /和E //不相同的部分组成的图(记为]\[//////)(E E EE G )是由一个或若干个欧拉子图所组成的.这是因为E /+E //中每个节点的度数均为偶数,而E /和E //的公共边数也是偶数,故]\[//////)(E E EE G 中每个节点的度数仍为偶数,所以它若为连通图时是一个欧拉图;若为非连通图时则由若干个欧拉子图组成.]\[//////)(E E EE G 的任何回路都由E /和E //中的边组成,而E /和E //在回路中的权数分别不大于该回路权数的一半,因而任何回路中属于E /中的权数之和与属于E //中的边数之和必定相等,所以ω(E /)=ω(E //).它就是最优附加边子集的权数,即E /和E //均为使附加边子集的权数达到最小的最优附加边子集.由定理3可得一个寻找邮递员问题最优解的方法.现举例如下:例1 已知邮递员要投递的街道如图11-20所示,试求最优邮路.解 先找出奇节点:A 1,A 2,A 3,A 4,B 1,B 2,B 3,B 4.奇节点进行配对,不妨把A 1与B 1,A 2与B 2,A 3与B 3,A 4与B 4配对,求其最短路.显然它不是最优解.下面我们根据定理3来进行调解.第一次调整:删去多于一条的重复边,即A 3与B 3,A 4与B 4中的(A 4,B 3).调整后,实际上成为A 1与B 1,A 2与B 2,A 3与A 4,B 3与B 4的配对,它们的最短路如图11-21所示. 第二次调整:发现在回路{A 1,A 2,B 2,A 4,B 3,B 4,B 1,A 1}中重复边的权数和为11,大于该回路权数20的一半.因而调整时,把该回路的重复边删去,代之以重复其余部分,得图11-22.可以看出,实际上是调整为A 1与A 2,B 1与B 4,A 3与A 4,B 2与B 3配对.第三次调整:在图11-22中发现回路{ A 3,A 4,B 2,A 3}中重复边的权数和为7,大于该回路权数10的一半,因而删去原重复边(A 3,V 2,A 4)和(A 4,B 2),而添加(B 2,A 3),得到图11-23.进行检查发现,既没有多于一条的重复边,也没有任何回路使其重复边的权数之和大于该回路的一半,因此图11-23就是最优的附加边子集E /,而G+E /为欧拉图,可由弗罗莱算法找出最优邮路.在现实生活中,很多问题都可以转化为中国邮递员问题,例如道路清扫时如何使开空车的总时间最少的问题等等.上面例1题所用的求最优邮路的方法叫“奇偶点图上作业法”.因为此方法要验证每个回路,很不方便,Edmods 和Johnson 在1973年提出一种比较有效的方法,有兴趣的读者可参考有关资料.习 题 11-31.证明,若图G 为欧拉图,则G 的边数不少于节点数.2.一名邮递员的投邮区,如下图11-24所示,每条边(街道)都有邮件需投递,各边旁所注的数字为该街道的长度,试求该邮区的最短投递路径及其长度. 3.求下列图11-25(a )(b)所示的投邮区的最佳邮路及其长度.【算法】欧拉图,欧拉回路,Eular Circuit ,随机生成欧拉图,搜索欧拉回路背景:图论起源于18世纪,1736年瑞士数学家欧拉(Eular )发表了图论的第一篇论文“哥尼斯堡七桥问题”。
欧拉回路存在的条件
欧拉回路存在的条件
能够有欧拉路径的条件:
1、在无向图中,所有边都是连通的
(1)存在欧拉路径的充分必要条件:度数为奇数的点只能有0或2个
(2)存在欧拉回路的充分必要条件:所有点的度数都是偶数
2、对于有向图,所有边都是连通的
(1)存在欧拉路径的充分必要条件:要么所有点的出度均等于入度;要么除了两个点之外,其余所有点的出度等于入度,剩余两个点;一个满足出度比入度多1(起点),另外一个满足入度比出度多1(终点)
(2)存在欧拉回路的充分必要条件:所有点的出度均等于入度。
2.3欧拉道路与回路
若v1邻接于vp,则v1,v2,…,vp,v1即为所 求的包含v1,v2,…,vp的一条H路。 若v1不邻接于vp,则假设与v1邻接的结 点集是{vL,vm,…,vj,…,vt}(k个结点), 2≤L,m,…,j,…,t≤p-1。可证明:vp必邻 接于vL-1,vm-1,…,vj-1,…,vt-1 中之一。如Vj-1,
由于C-a1是连通的,再在其中删除一个属于 S的结点a2后,最多有2个连通分支 (当a2为 割点时才有2个连通分支,否则仍是连通的), 故W(C-a1-a2)≤ 2。 假设割去L点后,W(C-a1-a2-…-aL)≤L。 再割去第aL+1点,这个点必属于某个连通分 支,去掉这个点后,该连通分支最坏变成2 个更小的连通分支了,故连通分数最多比原 来多1,即W(C-a1-a2-…-aL- aL+1) ≤L+1。故 W(C-S) ≤|S|。 而C-S与G-S的结点相同,但边比G-S少, 故 连通性不如G-S,故W(G-S) ≤W(C-S) ≤|S|
若vn不邻接于vi1-1,vi2-1,…,vik-1中任一 个(共K上),则vn至多邻接n-1-k个结点。 于是,deg(vn)≤(n-1)-k,deg(v1)=k, 故deg(vn)+deg(v1)≤n-1。 这与题设deg(vn)+deg(v1)≥n相矛盾。 不妨设vn邻接于vj-1,如下图所示
定理无向图G存在一条欧拉路G是连通的,且有0个 或2个奇数度结点。首尾相接的边构成路 证明:左右必要性 设G具有欧拉路V0e1V1e2…eiViei+1…ekvk,此路包 括图中所有边,则此路包括所有结点,所有点都在这 条路上, 任何两点之间都存在一条路,即任何两点都 是连通的,故G是连通的。 对任意一个中间结点Vi,在欧拉路中,Vi每出现 现一次必关联2条边,故Vi虽可重复出现,但deg(Vi) 必是偶数。 当端点V0=Vk,它是欧拉回路,该点也是中间点, 故Deg(Vi)也为偶数。 当端点V0Vk时,则在此欧拉路上,当这两个点作为 端点时各自只关联1条边,作为中间点关联偶数条边, 故总体看来,其度数为奇数。
3.仇荣琦《欧拉回路性质与应用探究》
欧拉回路性质与应用探究湖南师大附中 仇荣琦【摘要】欧拉回路,又称“一笔画”,是图论中可行遍性问题的一种。
本文首先介绍了欧拉回路的相关理论知识,以及求欧拉回路的算法。
然后通过几个实例,介绍了与欧拉回路相关的几类典型问题。
最后对欧拉回路的模型进行了总结,指出其特点和具备的优势。
【关键词】欧拉回路 欧拉路径【正文】一 引言欧拉回路问题是图论中最古老的问题之一。
它诞生于十八世纪的欧洲古城哥尼斯堡。
普瑞格尔河流经这座城市,人们在两岸以及河中间的两个小岛之间建了七座桥(如图1)。
市民们喜欢在这里散步,于是产生了这样一个问题:是否可以找到一种方案,使得人们从自己家里出发,不重复地走遍每一座桥,然后回到家中?这个问题如果用数学语言来描述,就是在图2中找出一条回路,使得它不重复地经过每一条边。
这便是著名的“哥尼斯堡七桥问题”。
无数热衷于此的人试图解决这个问题,但均以失败告终。
问题传到了欧拉(Leonhard图2图1Euler, 1707-1783)那里,立即引起了这位大数学家的重视。
经过悉心研究,欧拉终于在1736年发表了论文《哥尼斯堡的七座桥》,不但成功地证明了“七桥问题”无解,而且找到了对于一般图是否存在这类回路的充要条件。
后人为了纪念欧拉这位伟大的数学家,便将这类回路称为欧拉回路。
欧拉回路问题在信息学竞赛中有着广泛的应用,近年来在各类比赛中出现了许多与之相关的试题。
本文将介绍欧拉回路的相关理论知识,并通过几道例题分析欧拉回路的实际应用。
二 相关知识首先介绍相关概念和定理。
设),(E V G =是一个图。
欧拉回路 图G 中经过每条边一次并且仅一次的回路称作欧拉回路。
欧拉路径 图G 中经过每条边一次并且仅一次的路径称作欧拉路径。
欧拉图 存在欧拉回路的图称为欧拉图。
半欧拉图 存在欧拉路径但不存在欧拉回路的图称为半欧拉图。
在以下讨论中,假设图G 不存在孤立点1;否则,先将所有孤立点从图中删除。
显然,这样做并不会影响图G 中欧拉回路的存在性。
