• 欧拉路
    • 无向图中,S->T恰好不重不漏地经过每条边一次(可以经过重复的结点),称为S到T的欧拉路
    • S->T->S,称为S到T的欧拉回路,存在欧拉回路的无向图被称为欧拉图
  • 欧拉图的判定
    • 一张图为欧拉图,当且仅当无向图连通,并且每个点的度数都是偶数
    • 在判定了无向图存在欧拉回路之后,我们可以借助dfs和栈,求出欧拉回路的终点T,具体流程如下
      • void dfs(int x)
        • for each edge[x] ->y
          • if(!vis[x][y])
            • vis[x][y] = 1
            • dfs(y)
            • stack[++top] = y
      • int main()
        • dfs(1)
        • 倒序输出栈中所有的结点
    • 以上算法的复杂度为O(NM),因为点会被重复访问
    • 所以我们采用邻接表储存无向图,这样我们访问一条边之后,直接修改head[x]的值,跳过所有已经访问的边
    • 另外,欧拉回路DFS的递归层数是O(M)级别,容易造成系统栈溢出,我们可以采用另外一个栈,模拟及其的递归程序,把代码转化为非递归实现
    • 程序的时间复杂度为O(N+M)
      • #include<algorithm>
        #include <iostream>
        #include  <fstream>
        #include  <cstdlib>
        #include  <cstring>
        #include  <cassert>
        #include   <cstdio>
        #include   <vector>
        #include   <string>
        #include    <cmath>
        #include    <queue>
        #include    <stack>
        #include      <set>
        #include      <map>
        using namespace std;
        #define P(a,b,c) make_pair(a,make_pair(b,c))
        #define rep(i,a,n) for (int i=a;i<=n;i++)
        #define per(i,a,n) for (int i=n;i>=a;i--)
        #define CLR(vis) memset(vis,0,sizeof(vis))
        #define MST(vis,pos) memset(vis,pos,sizeof(vis))
        #define pb push_back
        //#define mp make_pair
        #define all(x) (x).begin(),(x).end()
        #define fi first
        #define se second
        #define SZ(x) ((int)(x).size())
        typedef pair<int,pair<int,int> >pii;
        typedef long long ll;
        typedef unsigned long long ull;
        const ll mod = 1000000007;
        const int INF = 0x3f3f3f3f;
        ll gcd(ll a, ll b) {
        	return b ? gcd(b, a%b) : a;
        }
        template<class T>inline void gmax(T &A, T B) {
        	(A<B)&&(A=B);//if(B>A)A=B;
        }
        template<class T>inline void gmin(T &A, T B) {
        	(A>B)&&(A=B);//if(B<A)A=B;
        }
        template <class T>
        inline bool scan(T &ret) {
        	char c;
        	int sgn;
        	if(c=getchar(),c==EOF) return 0; //EOF
        	while(c!='-'&&(c<'0'||c>'9')) c=getchar();
        	sgn=(c=='-')?-1:1;
        	ret=(c=='-')?0:(c-'0');
        	while(c=getchar(),c>='0'&&c<='9') ret=ret*10+(c-'0');
        	ret*=sgn;
        	return 1;
        }
        inline void outt(int x) {
        	if(x>9) outt(x/10);
        	putchar(x%10+'0');
        }
        const int N = 100010,M = 1000010;
        int head[N], ver[M], Next[M], tot;
        int STA[M], ans[M];
        bool vis[M];
        int n,m,top,t;
        
        void add(int x,int y){
        	ver[++tot] = y;
        	Next[tot] = head[x];
        	head[x] = tot;
        }
        
        void euler(){
        	STA[++top] = 1;
        	while(top>0){
        		int x = STA[top], i = head[x];
        		while(i && vis[i]) i=Next[i];
        		if(i){
        			STA[++top] = ver[i];
        			vis[i] = vis[i^1] = true;
        			head[x] = Next[i];
        		}else{
        			--top;
        			ans[++t] = x;
        		}
        	}
        }
        
        int main(){
        	cin>>n>>m;
        	tot = 1;
        	top = 0;
        	memset(head, 0 ,sizeof(head));
        	rep(i,1,m){
        		int x,y;
        		scanf("%d%d", &x, &y);
        		add(x,y), add(y,x); 
        	}
        	euler();
        	per(i,1,t){
        		printf("%d\n", ans[i]);
        	}
        	return 0; 
        }
  • 欧拉路的存在性判定
    • 一张无向图中存在欧拉路,当且仅当无向图连通,并且图中恰好有两个点的度数为奇数,其他点的度数都是偶数

发表评论

邮箱地址不会被公开。 必填项已用*标注