【图论】欧拉路浅谈
欧拉路
-
概念
欧拉路:在一个图中,可以从其中一点出发,不重复地走完其所有边,那么这个图就称为欧拉图。
如果起点和终相同,那么这个图为欧拉回路。
欧拉路路存在的充要条件:
1.图是连通的,若不连通不可能一次性遍历所有边。
2.对于无向图:有且仅有两个点,与其相连的边数为奇数,其他点相连边数为偶数;或所有点为偶数点。对于两个奇数点,一个为起点,一个为终点。起点需要出去,终点需要进入,所以与奇数个点相连。
如果存在这样一个欧拉路,其所有点相连边数都为偶数,那说明它是欧拉回路。
3.对于有向图:除去终点和起点,所有点的入度和出度相等。起点出度比入度大1,终点入度比出度大1.若起点和终点出入度也相同,则为欧拉回路。
欧拉路一般称为一笔画问题。
-
求解
DFS
设给定一张图,已知这张图是欧拉路,要求输出整条欧拉路。
此时可以采用DFS来遍历整张图,寻找欧拉路。
使用DFS寻找欧拉路的基本思想如下:
DFS寻找到第一个无边可走的节点,则这个节点必定为终点。
接下来由于DFS的递归回溯,会退回终点的上一个节点,继续往下搜索,直到寻找到第二个无边可走的节点,则这个节点必定为欧拉路中终点前最后访问的节点。
于是当通过DFS遍历完整张图后,就可以倒序储存下整个欧拉路。
#include<bits/stdc++.h> using namespace std; int edge[1000][1000]; //为了方便优先访问编号小的节点,这里使用邻接矩阵来存边 //如果使用vector来存图,那还需要对每个节点连接的边进行排序 int ans[1000000]; int degree[1000];//用于储存每个点的度,以求起点 int p=0; void dfs(int now) { for(int i=1;i<=1000;i++)//顺序寻找可访问的边,优先找编号小的节点 { if(edge[now][i])//若这条边尚未访问过 { edge[now][i]--;//已访问过的边要删去,防止重复访问 edge[i][now]--;//有向图的话请删去这一行 dfs(i); } } ans[++p]=now;//将访问的节点储存进答案数组 //由于递归的特性,这里储存的是逆序过程 } int main() { int n; cin>>n;//边的个数 for(int i=1;i<=n;i++) { int a,b; cin>>a>>b; edge[a][b]++; edge[b][a]++;//有向图的话删去这行 degree[a]++,degree[b]++;//两个点的度都+1 } int start=0; for(int i=1;i<=1000;i++) { if(degree[i]%2)//如果找到奇数点 { start=i;//那这个奇数点就作为起点,由于顺序遍历,这个起点编号必定最小 break; } } if(!start)//如果还没找到奇数点,说明是欧拉回路 { for(int i=1;i<=1000;i++) if(degree[i])//寻找最小的有度的点即可 { start=i; break; } } dfs(start);//dfs寻找欧拉路 for(int i=p;i>=1;i--) cout<<ans[i];//输出给定的欧拉路 return 0; }
Doctor,您还有许多事情需要处理。现在还不能休息哦。