无向图求欧拉路径,回路 模板(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("\n");
}
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;
}