无向图求欧拉路径,回路 模板(Hierholzer 算法)

定义:

欧拉回路:每条边恰好只走一次,并能回到出发点的路径

欧拉路径:经过每一条边一次,但是不要求回到起始点

欧拉回路存在性的判定:

无向图
每个顶点的度数都是偶数,则存在欧拉回路。

有向图
每个节顶点的入度都等于出度,则存在欧拉回路。

欧拉路径存在性的判定:

有向图 : 图连通,当且仅当该图所有顶点数的度数为0,或者一个顶点的度数为1,另一个顶点的度数为-1,其他顶点的度数为0。

无向图:图连通,当且仅当该图所有顶点的度数为偶数,或者除了两个度数为奇数外其余的全是偶数。

混合图(有的边是单向的,有的边是无向的。常被用于比喻城市里的交通网络有的路是单行道,有的路是双行道):

找到一个给每条无向的边定向的策略,使得每个顶点的入度等于出度,这样就能转换成上面第二种情况。

const int MAXN = 1005;

int G[MAXN][MAXN];//存图 
int cnt[MAXN];//存每个点度的奇偶性 
int N,M;//点个数,边条数 
stack<int> S;//存路径 

void dfs(int u){
    for(int v=1; v<=N; v++)
        if(G[u][v]){
            G[u][v]-=1;
            G[v][u]-=1;
            dfs(v);
            //不用恢复边!
        }
    S.push(u);//出栈时记录
}

inline void Print(){//输出路径 
	if(!S.empty()){
	    printf("%d",S.top());
	    S.pop();
	} 
	while(!S.empty()){
	    printf(" %d",S.top());
	    S.pop();
	}
	printf("
");
}

inline void init(){
	memset(cnt,0,sizeof cnt);
	memset(G,0,sizeof G);
}

int main(){
    while(scanf("%d %d",&N,&M) == 2){
    	init();
    	int u,v;
	    for(int i=1 ; i<=M ; ++i){
	        scanf("%d %d",&u,&v);
	        G[u][v] += 1;
	        G[v][u] += 1;
	        cnt[u] ^= 1;//利用了异或运算,0表示度为偶数,1表示度为奇数。
	        cnt[v] ^= 1;
	    }
	    for(u=1; u<=N ; ++u){//注意判断图是否从1点开始 
	        if(cnt[u]) break;
	    }
	    if(u == N+1) dfs(1);//都为偶节点,从随便一个开始都行 
	    else dfs(u);//从奇节点开始 
	    Print();
	}
   
    return 0;
}
原文地址:https://www.cnblogs.com/vocaloid01/p/9514023.html