一、欧拉路径的数学定义
欧拉路径是定义在图上的一种路径,满足经过图中的每条边恰好一次。
欧拉路径在无向图中存在的充要条件是图中度数为奇数的顶点有0个或2个,且所有顶点度数不为0,属于一个连通分量
在有向图中存在的充要条件是至多一个顶点 出度- 入度 = 1,至多一个顶点 入度 - 出度 = 1
二、欧拉回路的数学定义
欧拉回路是定义在图上的这样一种路:他的起点与终点相同,且经过图中每条边恰好一次。
欧拉回路在无向图上存在的充分必要条件是该图连通且所有顶点度数为偶数
在有向图上存在的充分必要条件是所有顶点出度和入度相同,且属于同一个强连通分量
三、无向图欧拉路径的求解方法
欧拉路径的求解方法一般是使用深度优先搜索(以下简称DFS)来做。
首先我们需要确定搜索的起点。如果度数全为偶数,由欧拉回路在无向图中存在的充要条件(图中顶点度数全为偶数)可知,搜索结果必定为一条环,所以用任何一个顶点当做起点都可以得到一条欧拉路径。如果有两个奇度数顶点,那么欧拉路径必定以一个顶点作为出发点,以另一个顶点作为终点。因此从两个顶点中选一个出来即可。关于这一点可以解释为:欧拉路径如果要经过所有的边,对于度数为偶数的点必定是“到达->离开”这样的访问形式,不会在此停留(也就是中间点),这可以解释两个奇度数顶点的情况,全偶度数顶点的情况可以理解为奇度数的出发点与奇度数的终点重合为同一个偶度数的点。
欧拉路径在无向图中的求解可以用“过河拆桥”来形容。通过定义我们可以得到:如果我们经过了一条边,那么在以后的搜索过程中我们不能再次经过这条边,因此要把这条边删除掉,使得搜索的过程中不会出现重复的情况。计算过程如下:
1.用图的数据初始化顶点,vis标记设为false。
2.按上述方法寻找起点,同时排除不合法情况。
3.从起点开始DFS,每次访问到顶点x的时候,将vis标记设为true,枚举x的邻接边,如果边没有被删除(del标记为false),那么就删除这条边(del设为true),同时找到下一个顶点,也删除这条边(无向图),DFS下一顶点,直到无法扩展,将顶点压栈。最后得到的栈按顺序出栈得到的序列就是顶点的访问顺序。
4.检查顶点的访问情况,如果有没有访问到的顶点就说明图不是连通图,不是合法情况。
#include<iostream>
#include<algorithm>
#include<vector>
#include<stack>
using namespace std;
struct edgetype
{
int to;
bool del;
};
struct pointtype
{
vector<edgetype> next;
bool vis;
int degree;
}point[100001];
stack<int> ans;
void dfs(int x)
{
point[x].vis=true;
vector<edgetype>::iterator it;
for(it=point[x].next.begin();it!=point[x].next.end();it++)
{
if((*it).del)
{
continue;
}
(*it).del=true;
vector<edgetype>::iterator jt;
for(jt=point[(*it).to].next.begin();jt!=point[(*it).to].next.end();jt++)
{
if((*jt).to==x)
{
(*jt).del=true;
break;
}
}
dfs((*it).to);
}
ans.push(x);
return;
}
int main()
{
int n,m;
cin>>n>>m;
for(int i=1;i<=n;i++)
{
point[i].next.clear();
point[i].vis=false;
point[i].degree=0;
}
for(int i=1;i<=m;i++)
{
int x,y;
cin>>x>>y;
edgetype tmp;
tmp.to=y;
tmp.del=false;
point[x].next.push_back(tmp);
tmp.to=x;
point[y].next.push_back(tmp);
point[x].degree+=1;
point[y].degree+=1;
}
int res=0;
int tip;
for(int i=1;i<=n;i++)
{
if(point[i].degree%2)
{
res+=1;
tip=i;
}
}
if(res!=0&&res!=2)
{
cout<<"Eulerian trail isn't exist!"<<endl;
return 0;
}
if(res==0)
{
tip=1;
}
dfs(tip);
bool flag=true;
for(int i=1;i<=n;i++)
{
if(point[i].vis==false)
{
flag=false;
break;
}
}
if(!flag)
{
cout<<"Eulerian trail isn't exist!"<<endl;
return 0;
}
cout<<ans.top();
ans.pop();
while(!ans.empty())
{
cout<<"->"<<ans.top();
ans.pop();
}
return 0;
}
View Code
四、有向图欧拉路径求解方法
与无向图欧拉路径求解方法类似,但是有以下改动:
1.如果顶点的入度和出度均相等,情况同无向图全偶度数顶点。如果顶点中有一个 出度 - 入度 = 1,有一个 入度 - 出度 = 1,那么用 入度 - 出度 = 1的顶点作为起点
2.删除边的时候只需要从起点删除一次即可
#include<iostream>
#include<algorithm>
#include<vector>
#include<stack>
using namespace std;
struct edgetype
{
int to;
bool del;
};
struct pointtype
{
vector<edgetype> next;
bool vis;
int in_degree;
int out_degree;
}point[100001];
stack<int> ans;
void dfs(int x)
{
point[x].vis=true;
vector<edgetype>::iterator it;
for(it=point[x].next.begin();it!=point[x].next.end();it++)
{
if((*it).del)
{
continue;
}
(*it).del=true;
dfs((*it).to);
}
ans.push(x);
return;
}
int main()
{
int n,m;
cin>>n>>m;
for(int i=1;i<=n;i++)
{
point[i].next.clear();
point[i].vis=false;
point[i].in_degree=0;
point[i].out_degree=0;
}
for(int i=1;i<=m;i++)
{
int x,y;
cin>>x>>y;
edgetype tmp;
tmp.to=y;
tmp.del=false;
point[x].next.push_back(tmp);
point[x].out_degree+=1;
point[y].in_degree+=1;
}
int res1=0,res2=0;
int tip;
for(int i=1;i<=n;i++)
{
if(point[i].in_degree-point[i].out_degree==1)
{
res1+=1;
}
if(point[i].out_degree-point[i].in_degree==1)
{
res2+=1;
tip=i;
}
}
bool flag=false;
if(res1==0&&res2==0)
{
flag=true;
}
if(res1==1&&res2==1)
{
flag=true;
}
if(!flag)
{
cout<<"Eulerian trail isn't exist!"<<endl;
return 0;
}
if(res1==0)
{
tip=1;
}
dfs(tip);
for(int i=1;i<=n;i++)
{
if(point[i].vis==false)
{
flag=false;
break;
}
}
if(!flag)
{
cout<<"Eulerian trail isn't exist!"<<endl;
return 0;
}
cout<<ans.top();
ans.pop();
while(!ans.empty())
{
cout<<"->"<<ans.top();
ans.pop();
}
return 0;
}
View Code
五、无向图欧拉回路求解方法
与无向图欧拉路径求解方法类似,判断存在与否的条件需要修改。
#include<iostream>
#include<algorithm>
#include<vector>
#include<stack>
using namespace std;
struct edgetype
{
int to;
bool del;
};
struct pointtype
{
vector<edgetype> next;
bool vis;
int degree;
}point[10001];
stack<int> ans;
void dfs(int x)
{
point[x].vis=true;
vector<edgetype>::iterator it;
for(it=point[x].next.begin();it!=point[x].next.end();it++)
{
if((*it).del)
{
continue;
}
(*it).del=true;
vector<edgetype>::iterator jt;
for(jt=point[(*it).to].next.begin();jt!=point[(*it).to].next.end();jt++)
{
if((*jt).to==x)
{
(*jt).del=true;
break;
}
}
dfs((*it).to);
}
ans.push(x);
}
int main()
{
int n,m;
cin>>n>>m;
for(int i=1;i<=n;i++)
{
point[i].next.clear();
point[i].vis=false;
point[i].degree=0;
}
for(int i=1;i<=m;i++)
{
int x,y;
cin>>x>>y;
edgetype tmp;
tmp.to=y;
tmp.del=false;
point[x].next.push_back(tmp);
point[x].degree+=1;
tmp.to=x;
point[y].next.push_back(tmp);
point[y].degree+=1;
}
bool flag=true;
for(int i=1;i<=n;i++)
{
if(point[i].degree%2)
{
flag=false;
break;
}
}
if(!flag)
{
cout<<"Eulerian trail isn't exist!"<<endl;
return 0;
}
dfs(1);
for(int i=1;i<=n;i++)
{
if(!point[i].vis)
{
flag=false;
break;
}
}
if(!flag)
{
cout<<"Eulerian trail isn't exist!"<<endl;
return 0;
}
cout<<ans.top();
ans.pop();
while(!ans.empty())
{
cout<<"->"<<ans.top();
ans.pop();
}
return 0;
}
View Code
六、有向图欧拉回路求解方法
与有向图欧拉路径求解方法类似,判断存在与否的条件需要修改。
#include<iostream>
#include<algorithm>
#include<vector>
#include<stack>
using namespace std;
struct edgetype
{
int to;
bool del;
};
struct pointtype
{
vector<edgetype> next;
bool vis;
int in_degree;
int out_degree;
}point[10001];
stack<int> ans;
void dfs(int x)
{
point[x].vis=true;
vector<edgetype>::iterator it;
for(it=point[x].next.begin();it!=point[x].next.end();it++)
{
if((*it).del)
{
continue;
}
(*it).del=true;
dfs((*it).to);
}
ans.push(x);
}
int main()
{
int n,m;
cin>>n>>m;
for(int i=1;i<=n;i++)
{
point[i].next.clear();
point[i].vis=false;
point[i].in_degree=0;
point[i].out_degree=0;
}
for(int i=1;i<=m;i++)
{
int x,y;
cin>>x>>y;
edgetype tmp;
tmp.to=y;
tmp.del=false;
point[x].next.push_back(tmp);
point[x].out_degree+=1;
point[y].in_degree+=1;
}
bool flag=true;
for(int i=1;i<=n;i++)
{
if(point[i].in_degree!=point[i].out_degree)
{
flag=false;
break;
}
}
if(!flag)
{
cout<<"Eulerian trail isn't exist!"<<endl;
return 0;
}
dfs(1);
for(int i=1;i<=n;i++)
{
if(!point[i].vis)
{
flag=false;
break;
}
}
if(!flag)
{
cout<<"Eulerian trail isn't exist!"<<endl;
return 0;
}
cout<<ans.top();
ans.pop();
while(!ans.empty())
{
cout<<"->"<<ans.top();
ans.pop();
}
return 0;
}
View Code