欧拉回路(无向图,有向图,混合图)

1. uoj#117 欧拉回路

        给无向图和有向图两种图,判断是否存在并输出其欧拉回路

        板子题。。。

        无向图欧拉回路存在条件:所有点度数为偶数且所有边连通

        有向图欧拉回路存在条件:所有点出度等于入度且所有边连通

       

#include<stdio.h>
#include<iostream>
#include<vector>
#include<algorithm>
#include<queue>
#include<math.h>
#include<string.h>
using namespace std;

const int N=1e6;
int p[N],head[N],nex[N],e=1;
int in[N],out[N],vis[N];
vector<int>g;
void add(int a,int b){
    p[++e]=b;
    nex[e]=head[a];
    head[a]=e;
}
void dfs(int u){
    int v,now;
    for(int &i=head[u];i;i=nex[i]){   //需加当前弧优化,否则可卡到 m^2
        if(vis[i/2]==0){
             vis[i/2]=1;
             v=p[i];
             now=i;
             dfs(v);
             g.push_back(now);
       }
    }
}

int main(){
    int a,b,i,n,m,t;
    scanf("%d",&t);    //t为1表示无向图,否则为有向图
    scanf("%d%d",&n,&m);

    if(m==0){
        printf("YES\n");
        return 0;
    }
    for(i=1;i<=m;i++){
        scanf("%d%d",&a,&b);
        if(t==1){
            add(a,b);
            add(b,a);
            out[a]++;
            out[b]++;
        }
        else{
            add(a,b);
            out[a]++;
            in[b]++;
            e++;
        }
    }

    int ans=1;
    if(t==1){
        for(i=1;i<=n;i++) if(out[i]%2) ans=0;
    }
    else{
        for(i=1;i<=n;i++) if(out[i]!=in[i]) ans=0;
    }
    if(ans==0) printf("NO\n");
    else{
        for(i=1;i<=n;i++) if(in[i]) a=i;
        dfs(a);
        if(g.size()!=m) printf("NO\n");    //判断边是否连通
        else{
            printf("YES\n");
            for(i=g.size()-1;i>=0;i--){
               a=g[i]/2;
               if(g[i]%2) a*=-1;
               printf("%d ",a);
            }
        }
    }
}



2. UVA10735 混合图欧拉回路

由于图中存在无向边和有向边,不能直接判断是否存在欧拉回路,所以需要对无向边重新定向转成有向图处理。

先对所有的无向边任意定向,若定向后存在一个点的入度与出度差为奇数,则显然不存在欧拉回路(因为将一条无向边反向后端点入度与出度差的奇偶性不变,要想差变为0则初始差要为偶数)

任意定向无向边后,考虑使用网络流进行反悔操作

建图:

   (1) 令d[i]=(out[i]-in[i])/2, 若d[i]>0,超级源点S向i连容量为d[i]的边;否则i向超级汇点T连容量为-d[i]的边

   (2)对于一条定向为u -> v的无向边,u向v连容量为1的边

跑最大流,不是满流则不存在欧拉回路;考虑反悔情况,若一条无向边对应的剩余容量为0,则说明该无向边反悔,将其反向

得到有向图后跑有向图欧拉回路即可。。。

#include<stdio.h>
#include<iostream>
#include<vector>
#include<algorithm>
#include<queue>
#include<math.h>
#include<string.h>
using namespace std;

const int N=10000,inf=1e9;

struct FLOW{
    int p[N],nex[N],head[N],c[N],e;
    int dp[N],s,t;
    queue<int>q;

    void add(int a,int b,int x){
        p[++e]=b;
        nex[e]=head[a];
        head[a]=e;
        c[e]=x;

        p[++e]=a;
        nex[e]=head[b];
        head[b]=e;
        c[e]=0;
    }
    int bfs(){
        int i,u,v;
        for(i=1;i<=t;i++) dp[i]=inf;
        dp[s]=0;
        for(q.push(s);q.size();q.pop()){
            u=q.front();
            for(i=head[u];i;i=nex[i]){
                v=p[i];
                if(c[i]&&dp[v]>dp[u]+1){
                    dp[v]=dp[u]+1;
                    q.push(v);
                }
            }
        }
        return dp[t]!=inf;
    }
    int dfs(int u,int f){
        if(u==t||f==0) return f;
        int i,v,k,sum=0;
        for(i=head[u];i;i=nex[i]){
            v=p[i];
            if(dp[v]==dp[u]+1&&c[i]){
                 k=dfs(v,min(c[i],f-sum));
                 sum+=k;
                 c[i]-=k;
                 c[i^1]+=k;
                 if(sum==f) break;
            }
        }
        if(sum==0) dp[u]=-1;
        return sum;
    }
    int maxflow(){
        int ans=0;
        while(bfs()) ans+=dfs(s,inf);
        return ans;
    }
    void init(){
         e=1;
         memset(head,0,sizeof(head));
    }
}F;


int in[N],out[N],id[N];
struct E{
    int a,b;
    char s[5];
}A[N];

int ck(int n){
    int i;
    for(i=1;i<=n;i++) if((in[i]-out[i])%2) return 0;
    return 1;
}

struct EULER{
    int p[N],nex[N],head[N],vis[N],e;
    vector<int>g;
    void add(int a,int b){
        p[++e]=b;
        nex[e]=head[a];
        head[a]=e;
    }
    void dfs(int u){
        int v,now;
        for(int &i=head[u];i;i=nex[i]){
           v=p[i];
           if(vis[i/2]==0){
               vis[i/2]=1;
               now=i;
               dfs(v);
               g.push_back(now);
           }
        }
    }
    void init(){
         g.clear();
         memset(head,0,sizeof(head));
         memset(vis,0,sizeof(vis));
         e=1;
    }
}B;

int main(){
    int i,n,a,b,t,m;
    char s[10];
    scanf("%d",&t);
    while(t--){
       scanf("%d%d",&n,&m);
       for(i=1;i<=n;i++)  in[i]=out[i]=0;
       F.init();
       for(i=1;i<=m;i++){
           scanf("%d%d%s",&A[i].a,&A[i].b,A[i].s);   //s为U为无向边,否则有向边
           out[A[i].a]++;
           in[A[i].b]++;
       }
       if(ck(n)==0) printf("No euler circuit exist\n");
       else{
           F.s=n+1;
           F.t=n+2;
           int sum=0,root;
           for(i=1;i<=n;i++){
               a=(out[i]-in[i])/2;
               if(a>0)  F.add(F.s,i,a);
               else F.add(i,F.t,-a);
               if(a>0) sum+=a;
           }
           for(i=1;i<=m;i++){
               if(A[i].s[0]=='U'){
                    id[i]=F.e+1;
                    F.add(A[i].a,A[i].b,1);
                }
           }
           sum-=F.maxflow();
           if(sum) printf("No euler circuit exist\n");
           else{
                B.init();
                for(i=1;i<=m;i++){
                     if(A[i].s[0]=='U'&&F.c[id[i]]==0) swap(A[i].a,A[i].b);
                     B.add(A[i].a,A[i].b);
                     B.e++;
                     root=A[i].a;
                }
                B.dfs(root);
                if(B.g.size()!=m) printf("No euler circuit exist\n");
                else{
                     printf("%d",root);
                     for(i=B.g.size()-1;i>=0;i--){
                         a=B.g[i];
                         printf(" %d",B.p[a]);
                     }
                     printf("\n");
                }
           }
       }
       printf("\n");
    }
    return 0;

}

 

 

  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值