• UVa 10735 (混合图的欧拉回路) Euler Circuit


    题意:

    给出一个图,有的边是有向边,有的是无向边。试找出一条欧拉回路。

    分析:

    按照往常的思维,遇到混合图,我们一般会把无向边拆成两条方向相反的有向边。

    但是在这里却行不通了,因为拆成两条有向边的话,就表示这个边能“在两个相反方向各经过一次”。

    而题意是这个边只能经过一次。

    假设图中存在欧拉回路,则所有点的出度out(i) 等于 入度in(i)

    不妨这样,先将所有的无向边任意定向,对于out(u) > in(u)的点,可以将已经定向的无向边u->v反向为v->u,这样out(u) - in(u)的值减2

    如果把出度看做“货物”,则out(u) > in(u)的点提供货物,out(u) < in(u)的点需要货物,所以我们可以用网络流求最大流的算法,来使“供需平衡”

    具体来说就是,给已经定向的无向边两点之间连一条容量为1的边,连接源点 与 所有“提供”出度的点,连接 所有“需要”出度的点 与 汇点。

    如果求出来的最大流满载,也就是所有的出度都能被运到需要的地方,则有解。

    在最大流中,如果流量为1则代表将该边反向的操作。

    所以再建一个新图来求欧拉回路。

    本题还有一个坑点就是可能存在平行边,所以求欧拉路径的过程中用 vis[u][v] = 1;的方法是行不通的了。

      1 #include <bits/stdc++.h>
      2 #define REP(i,n) for(int i = 0; i < (n); i++)
      3 #define PB push_back
      4 using namespace std;
      5 
      6 const int INF = 1000000000;
      7 const int maxn = 500 + 10;
      8 
      9 struct Edge
     10 {
     11     int from, to, cap, flow;
     12     Edge(int u, int v, int c, int f):from(u), to(v), cap(c), flow(f) {}
     13 };
     14 
     15 struct EdmondsKarp
     16 {
     17     int n, m;
     18     vector<Edge> edges;
     19     vector<int> G[maxn];
     20     int a[maxn], p[maxn];
     21 
     22     void Init(int n)
     23     {
     24         REP(i, n) G[i].clear();
     25         edges.clear();
     26     }
     27 
     28     void AddEdge(int from, int to, int cap)
     29     {
     30         edges.PB(Edge(from, to, cap, 0));
     31         edges.PB(Edge(to, from, 0, 0));
     32         m = edges.size();
     33         G[from].PB(m-2);
     34         G[to].PB(m-1);
     35     }
     36 
     37     int MaxFlow(int s, int t)
     38     {
     39         int flow = 0;
     40         for(;;)
     41         {
     42             queue<int> Q;
     43             Q.push(s);
     44             memset(a, 0, sizeof(a));
     45             a[s] = INF;
     46             while(!Q.empty())
     47             {
     48                 int x = Q.front(); Q.pop();
     49                 REP(i, G[x].size())
     50                 {
     51                     Edge& e = edges[G[x][i]];
     52                     if(!a[e.to] && e.cap > e.flow)
     53                     {
     54                         a[e.to] = min(a[x], e.cap - e.flow);
     55                         p[e.to] = G[x][i];
     56                         Q.push(e.to);
     57                     }
     58                 }
     59                 if(a[t]) break;
     60             }
     61             if(!a[t]) break;
     62             for(int u = t; u != s; u = edges[p[u]].from)
     63             {
     64                 edges[p[u]].flow += a[t];
     65                 edges[p[u]^1].flow -= a[t];
     66             }
     67             flow += a[t];
     68         }
     69         return flow;
     70     }
     71 }g;
     72 
     73 int n, m;
     74 int deg[maxn], u[maxn], v[maxn], id[maxn];
     75 bool directed[maxn];
     76 
     77 vector<int> G[maxn];//建新图,用来求欧拉回路
     78 vector<int> vis[maxn];
     79 vector<int> path;//欧拉回路
     80 
     81 void Euler(int u)
     82 {
     83     REP(i, G[u].size()) if(!vis[u][i])
     84     {
     85         vis[u][i] = 1;
     86         Euler(G[u][i]);
     87         path.PB(G[u][i]+1);
     88     }
     89 }
     90 
     91 void print_answer()
     92 {
     93     REP(i, n) { G[i].clear(); vis[i].clear(); }
     94     REP(i, m)
     95     {
     96         bool rev = false;
     97         if(!directed[i] && g.edges[id[i]].flow > 0) rev = true;//流量为1对应将该边反向
     98         if(!rev) { G[u[i]].PB(v[i]); vis[u[i]].PB(0); }
     99         else { G[v[i]].PB(u[i]); vis[v[i]].PB(0); }
    100     }
    101 
    102     path.clear();
    103     Euler(0);
    104     printf("1");
    105     for(int i = path.size()-1; i >= 0; i--) printf(" %d", path[i]);
    106     puts("");
    107 }
    108 
    109 int main()
    110 {
    111     //freopen("in.txt", "r", stdin);
    112 
    113     int T;
    114     scanf("%d", &T);
    115     while(T--)
    116     {
    117         scanf("%d%d", &n, &m);
    118         g.Init(n+2);
    119         memset(deg, 0, sizeof(deg));
    120         REP(i, m)
    121         {
    122             char d;
    123             scanf("%d %d %c", &u[i], &v[i], &d);
    124             u[i]--; v[i]--;
    125             directed[i] = (d == 'D');
    126             deg[u[i]]++; deg[v[i]]--;
    127             if(!directed[i]) { id[i] = g.edges.size(); g.AddEdge(u[i], v[i], 1); }//第i条边在网络流中的编号
    128         }
    129 
    130         bool ok = true;
    131         REP(i, m) if(deg[i] % 2 != 0) { ok = false; break; }//出入度之和不是偶数说明不存在欧拉回路
    132 
    133         int s = n, t = n+1;
    134         if(ok)
    135         {
    136             int sum = 0;
    137             REP(i, n)
    138             {
    139                 if(deg[i] > 0) { sum += deg[i] / 2; g.AddEdge(s, i, deg[i] / 2); }
    140                 if(deg[i] < 0) { g.AddEdge(i, t, -deg[i] / 2); }
    141             }
    142             int flow = g.MaxFlow(s, t);
    143             if(flow != sum) ok = false;//最大流不满载
    144         }
    145 
    146         if(ok) print_answer(); else puts("No euler circuit exist");
    147         if(T) puts("");
    148     }
    149 
    150     return 0;
    151 }
    代码君
  • 相关阅读:
    【LibreOJ】#6257. 「CodePlus 2017 12 月赛」可做题2
    【Atcoer】ARC088 E
    【Atcoder】ARC088 D
    【CodeForces】671 D. Roads in Yusland
    【CodeForces】671 B. Robin Hood
    【CodeForces】671 C. Ultimate Weirdness of an Array
    【CodeForces】679 A. Bear and Prime 100
    【CodeForces】679 B. Bear and Tower of Cubes
    【BZOJ】3262: 陌上花开
    【CodeForces】899 F. Letters Removing
  • 原文地址:https://www.cnblogs.com/AOQNRMGYXLMV/p/4296449.html
Copyright © 2020-2023  润新知