欧拉路问题(学习笔记)

欧拉路问题,俗称("一笔画"问题)

定义:给定一张无向图,若存在一条从\(S\)\(T\)的路径,恰好不重不漏地经过每条边一次(可以重复经过图中的节点),则称该路径为\(S\)\(T\)的欧拉路.

特别地,若存在一条从\(S\)出发的路径,恰好不重不漏地经过每条边一次(可以重复经过图中的节点),最终回到起点\(S\),则该路径为欧拉回路.

存在欧拉回路的无向图称作欧拉图.

欧拉图的判定:一张无向图为欧拉图,当且仅当无向图连通,并且每个点的度数都是偶数.

欧拉路的存在性判定:一张无向图中存在欧拉路,当且仅当无向图连通,并且图中恰好有两个节点的度数为奇数,其它节点的度数都是偶数.这两个度数为奇数的点就是欧拉路的起点\(S\)和终点\(T\).

inline void add(int a,int b){
    nxt[++tot]=head[a];head[a]=tot;to[tot]=b;
}
inline void oula(){
    st[++top]=1;//入栈
    while(top>0){
        int u=st[top],i=head[u];
        while(i&&visit[i])i=nxt[i];//找到一条没有被访问过的边
        if(i){
            st[++top]=to[i];
            visit[i]=visit[i^1]=1;
//标记为访问过,这里体现了tot=1的好处,每一条边被两个方向存储
//数组下标一定是2,3或者4,5这种异或1能够互相得到的
            head[u]=nxt[i];
        }
        else --top,ans[++sum]=u;
//u相连的所有边均被访问过,则回溯.
    }
}
int main(){
    int n=read(),m=read();tot=1;
    for(int i=1;i<=m;++i){
        int a=read(),b=read();
        add(a,b);add(b,a);
    }
    oula();
    for(int i=sum;i>=1;--i)printf("%d\n",ans[i]);//倒序输出
}

POJ,来一道模板题练练手.

题意:给定\(N(N<=10000)\)个点\(M(M<=50000)\)条边的无向图,求一条路径,从节点1出发,最后回到节点1,并且满足每条边恰好被正反两个方向分别经过一次.若有多种方案,输出任意一种即可.

分析:求欧拉回路的问题.在上述模板的基础上,去掉\(visit\)数组的标记即可保证每条边恰好被正反两个方向分别经过一次.

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<queue>
#include<map>
#include<set>
#define ll long long
using namespace std;
inline int read(){
    int x=0,o=1;char ch=getchar();
    while(ch!='-'&&(ch<'0'||ch>'9'))ch=getchar();
    if(ch=='-')o=-1,ch=getchar();
    while(ch>='0'&&ch<='9')x=x*10+ch-'0',ch=getchar();
    return x*o;
}
const int N=100005;
int n,m;
int top,sum,st[N],ans[N];
int tot,head[N],nxt[N],to[N];
inline void add(int a,int b){
    nxt[++tot]=head[a];head[a]=tot;to[tot]=b;
}
inline void oula(){
    st[++top]=1;
    while(top>0){
        int u=st[top],i=head[u];
        if(i){
            st[++top]=to[i];
            head[u]=nxt[i];
        }
        else --top,ans[++sum]=u;
    }
}
int main(){
    n=read();m=read();
    for(int i=1;i<=m;++i){
        int a=read(),b=read();
        add(a,b);add(b,a);
    }
    oula();
    for(int i=sum;i>=1;--i)printf("%d\n",ans[i]);
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/PPXppx/p/11575334.html