首页 > 其他 > 详细

【笔记】欧拉(回)路

时间:2018-06-02 10:09:10      阅读:202      评论:0      收藏:0      [点我收藏+]

对于一张图G,若存在一条从S出发到T的路径,使得图中每条边都恰好只经过一次(点可以经过多次!),则该路径为S到T的欧拉路径。

若一条回路(从S出发最终回到S),使得图中每条边都恰好只经过一次,则该路径为图G的一条欧拉回路。

对于存在欧拉回路无向图,称为欧拉图。

定理1:若无向图中存在欧拉路径,当且仅当无向图连通,且图中恰有两个点的度数为奇数(S和T),其他点的度数都是偶数。

定理2:若无向图中存在欧拉回路,当且仅当无向图连通,且图中每个点的度数都是偶数。

->若一个点的度数为偶数,说明只要到达该点,就必定可通过一条尚未走过的边离开该点

Code:

一.邻接矩阵存图

int e[N][N];//两点间有多条边的情况 
//bool e[N][N]; 两点间只有一条边的情况 
bool vis[M<<1];
int ans[N<<2],top;
//存储路径 P.S.数组开大些,因为每个点都可能经过多次 
void dfs(int u){
    for(int i=1;i<=n;i++){
        //↑从小到大遍历,可以保证字典序最小! 
        if(e[u][i]){
            e[u][i]--;
            e[i][u]--;
            //e[u][i]=e[i][u]=0;
            dfs(i);
        } 
    }
    ans[++top]=u; 
}
int deg[N];//记录每个点的度数,用来判断是否存在欧拉(回)路 
int main(){
    scanf....
    for(int i=1;i<=m;i++){
        scanf("%d%d",&u,&v);
        e[u][v]++;
        e[v][u]++;
        //e[u][v]=e[v][u]=1;
    }
    int cnt=0,root=inf;
    for(int i=1;i<=n;i++){
        if(deg[i]%2){
            cnt++;
            //root=min(root,i); 可以保证字典序最小 
        }
    }
    if(cnt&&cnt!=2) printf("有奇数度数的点的个数不为2 不存在欧拉路径");
    if(!cnt) root=1;//所有点的度数都是偶数 存在欧拉回路 root=1保证字典序最小。
    dfs(root);
    for(int i=top;i;i--){
        printf("%d\n",ans[i]);
    } //欧拉(回)路是递归遍历的,因此路径是倒序存储的,所以输出时倒序输出。 
}

二.邻接表存图(题目要求字典序最小时最好不要用邻接表存图,因为遍历的顺序不能保证字典序最小)

struct node{
    int to,nxt;
}e[M<<1];
int head[N],tot=1;//tot=1 成对变换 边i与边i^1互为反向边 
void add(int u,int v){
    e[++tot]=(node){v,head[u]};
    head[u]=tot; 
}
bool vis[M<<1];
int ans[N<<2],top;
//存储路径 P.S.数组开大些,因为每个点都可能经过多次 
void dfs(int u){
    for(int i=head[u];i;i=e[i].nxt){
        if(!vis[i]){
            int v=e[i].to;
            vis[i]=vis[i^1]=1;
            head[u]=e[i].nxt;
            //遍历到边i时,前i-1条边都已遍历过,为避免重复操作,直接把head[u]变为next[i] 
            dfs(v);
        } 
    }
    ans[++top]=u; 
}
int deg[N];//记录每个点的度数,用来判断是否存在欧拉(回)路 
int main(){
    scanf....
    for(int i=1;i<=m;i++){
        scanf("%d%d",&u,&v);
        add(u,v);
        deg[v]++;
        add(v,u);
        deg[u]++; 
    }
    int cnt=0,root=inf;
    for(int i=1;i<=n;i++){
        if(deg[i]%2){
            cnt++;
            root=min(root,i)
        }
    }
    if(cnt&&cnt!=2) printf("有奇数度数的点的个数不为2 不存在欧拉路径");
    if(!cnt) root=1;//所有点的度数都是偶数 存在欧拉回路 
    dfs(root);
    for(int i=top;i;i--){
        printf("%d\n",ans[i]);
    } //欧拉(回)路是递归遍历的,因此路径是倒序存储的,所以输出时倒序输出。 
}

 

【笔记】欧拉(回)路

原文:https://www.cnblogs.com/Loi-Brilliant/p/9124327.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!