• POJ 1637 混合图的欧拉回路判定


    题意:一张混合图,判断是否存在欧拉回路。

    分析参考:

    混合图(既有有向边又有无向边的图)中欧拉环、欧拉路径的判定需要借助网络流!

    (1)欧拉环的判定:
    一开始当然是判断原图的基图是否连通,若不连通则一定不存在欧拉环或欧拉路径(不考虑度数为0的点)。

    其实,难点在于图中的无向边,需要对所有的无向边定向(指定一个方向,使之变为有向边),使整个图变成一个有向欧拉图(或有向半欧拉图)。若存在一个定向满足此条件,则原图是欧拉图(或半欧拉图)否则不是。关键就是如何定向?

    首先给原图中的每条无向边随便指定一个方向(称为初始定向),将原图改为有向图G',然后的任务就是改变G'中某些边的方向(当然是无向边转化来的,原混合图中的有向边不能动)使其满足每个点的入度等于出度。
    设D[i]为G'中(点i的出度 - 点i的入度)。可以发现,在改变G'中边的方向的过程中,任何点的D值的奇偶性都不会发生改变(设将边<i, j>改为<j, i>,则i入度加1出度减1,j入度减1出度加1,两者之差加2或减2,奇偶性不变)!而最终要求的是每个点的入度等于出度,即每个点的D值都为0,是偶数,故可得:若初始定向得到的G'中任意一个点的D值是奇数,那么原图中一定不存在欧拉环!

    若初始D值都是偶数,则将G'改装成网络:设立源点S和汇点T,对于每个D[i]>0的点i,连边<S, i>,容量为D[i]/2;对于每个D[j]<0的点j,连边<j, T>,容量为-D[j]/2;G'中的每条边在网络中仍保留,容量为1(表示该边最多只能被改变方向一次)。求这个网络的最大流,若S引出的所有边均满流,则原混合图是欧拉图,将网络中所有流量为1的中间边(就是不与S或T关联的边)在G'中改变方向,形成的新图G''一定是有向欧拉图;若S引出的边中有的没有满流,则原混合图不是欧拉图。

    为什么能这样建图?
    考虑网络中的一条增广路径S-->i-->...-->j-->T,将这条从i到j的路径在G'中全部反向,则:i的入度加1出度减1,j的入度减1出度加1,路径中其它点的入度出度均不变。而i是和S相连的,因此初始D[i]>0,即i的出度大于入度,故这样反向之后D[i]减少2;同理,j是和T相连的,这样反向之后D[j]增加2。因此,若最大流中边<S, i>满流(流量为初始D[i]/2),此时D[i]值就变成了0,也就是i的入度等于出度。因此只要使所有S引出的边全部满流,所有初始D值>0的点的D值将等于0,又因为将边变向后所有点的D值之和不变,所有初始D值小于0的点的D值也将等于0,而初始D值等于0的D点既不与S相连也不与T相连,所以它们是网络中的中间点,而中间点的流入量等于流出量,故它们的入度和出度一直不变,即D值一直为0。因此,整个图G'成为欧拉图。
    (2)欧拉路径的判定:
    首先可以想到的是枚举欧拉路径的起点i和终点j,然后在图中添加边<j, i>,再求图中是否有欧拉回路即可。但是,该算法的时间复杂度达到了O(M * 最大流的时间),需要优化。
    前面已经说过,在将边变向的过程中任何点的D值的奇偶性都不会改变,而一个有向图有欧拉路径的充要条件是基图连通且有且只有一个点的入度比出度少1(作为欧拉路径的起点),有且只有一个点的入度比出度多1(作为终点),其余点的入度等于出度。这就说明,先把图中的无向边随便定向,然后求每个点的D值,若有且只有两个点的初始D值为奇数,其余的点初始D值都为偶数,则有可能存在欧拉路径(否则不可能存在)。进一步,检查这两个初始D值为奇数的点,设为点i和点j,若有D[i]>0且D[j]<0,则i作起点j作终点(否则若D[i]与D[j]同号则不存在欧拉路径),连边<j, i>,求是否存在欧拉环即可(将求出的欧拉环中删去边<j, i>即可)。这样只需求一次最大流。
    就是转化成最大流,最一次最大流,看是不是满流

      1 #include <iostream>
      2 #include <cstdlib>
      3 #include <cstdio>
      4 #include <string>
      5 #include <cstring>
      6 #include <cmath>
      7 #include <vector>
      8 #include <queue>
      9 #include <algorithm>
     10 #include <map>
     11 using namespace std;
     12 const int maxn = 220;
     13 const int maxm = maxn*maxn;
     14 const int INF = 0x3f3f3f3f;
     15 struct Edge
     16 {
     17     int from, to, cap, flow;
     18     Edge(int from, int to, int cap, int flow): from(from), to(to), cap(cap), flow(flow) {}
     19 };
     20 struct Dinic
     21 {
     22     int n, m, s, t;
     23     vector<Edge> edges;
     24     vector<int> G[maxn];
     25     bool vis[maxn];
     26     int d[maxn];
     27     int cur[maxn];
     28     void init(int n)
     29     {
     30         this->n = n;
     31         for(int i = 0; i <= n; i++) G[i].clear();
     32         edges.clear();
     33     }
     34     void ClearFlow ()
     35     {
     36         for(int i = 0; i < edges.size(); i++) edges[i].flow = 0;
     37     }
     38     void AddEdge(int from, int to, int cap)
     39     {
     40         edges.push_back(Edge (from, to, cap, 0));
     41         edges.push_back(Edge (to, from, 0, 0));
     42         m = edges.size();
     43         G[from].push_back(m-2);
     44         G[to].push_back(m-1);
     45     }
     46     bool BFS()
     47     {
     48         memset(vis, 0, sizeof(vis));
     49         queue<int> Q;
     50         Q.push(s);
     51         d[s] = 0;
     52         vis[s] = 1;
     53         while(!Q.empty())
     54         {
     55             int x = Q.front();
     56             Q.pop();
     57             for(int i = 0; i < G[x].size(); i++)
     58             {
     59                 Edge& e = edges[G[x][i]];
     60                 if(!vis[e.to] && e.cap > e.flow)
     61                 {
     62                     vis[e.to] = 1;
     63                     d[e.to] = d[x]+1;
     64                     Q.push(e.to);
     65                 }
     66             }
     67         }
     68         return vis[t];
     69     }
     70     int DFS(int x, int a)
     71     {
     72         if(x == t || a == 0) return a;
     73         int flow = 0, f;
     74         for(int &i = cur[x]; i < G[x].size(); i++)
     75         {
     76             Edge& e = edges[G[x][i]];
     77             if(d[x] + 1 == d[e.to] && (f = DFS(e.to, min(a, e.cap-e.flow))) > 0)
     78             {
     79                 e.flow += f;
     80                 edges[G[x][i]^1].flow -= f;
     81                 flow += f;
     82                 a -= f;
     83                 if(a == 0) break;
     84             }
     85         }
     86         return flow;
     87     }
     88     int Maxflow(int s, int t)
     89     {
     90         this->s = s;
     91         this->t = t;
     92         int flow = 0;
     93         while(BFS())
     94         {
     95             memset(cur, 0, sizeof(cur));
     96             flow += DFS(s, INF);
     97         }
     98         return flow;
     99     }
    100 };
    101 int fa[maxn];
    102 int find(int x)
    103 {
    104     return x == fa[x]? x : fa[x] = find(fa[x]);
    105 }
    106 void Union(int x, int y)
    107 {
    108     x = find(x), y = find(y);
    109     if(x != y) fa[x] = y;
    110 }
    111 Dinic dinic;
    112 int n, m, s, t;
    113 int ind[maxn], outd[maxn];
    114 bool vis[maxn];
    115 struct Edge2
    116 {
    117     int v;
    118     bool vis;
    119     int next;
    120 } edge[maxm];
    121 int cnt;
    122 int first[maxn];
    123 void addedge(int u, int v)
    124 {
    125     edge[cnt].v = v, edge[cnt].vis = 0;
    126     edge[cnt].next = first[u], first[u] = cnt++;
    127 }
    128 void init()
    129 {
    130     cnt = 0;
    131     memset(first, -1, sizeof(first));
    132     memset(ind, 0, sizeof(ind));
    133     memset(outd, 0, sizeof(outd));
    134     memset(vis, 0, sizeof(vis));
    135     for(int i = 0; i <= n+2; i++) fa[i] = i;
    136 }
    137 void read_case()
    138 {
    139     scanf("%d%d",&n,&m);
    140     init();
    141     dinic.init(n+5);
    142     while(m--)
    143     {
    144         int x, y;
    145         char c;
    146         scanf("%d %d %c", &x, &y, &c);
    147         if(c == '1')
    148             addedge(x, y);
    149         else if(c == '0')
    150             dinic.AddEdge(x, y, 1);
    151         vis[x] = vis[y] = 1;
    152         outd[x]++, ind[y]++;
    153         Union(x, y);
    154     }
    155 }
    156 int totflow;
    157 int build()
    158 {
    159     s = 0, t = n+1;
    160     totflow = 0;
    161     for(int i = 1; i <= n; i++)
    162         if(vis[i])
    163         {
    164             if((outd[i]+ind[i]) & 1)
    165                 return 0;
    166             else if(outd[i] > ind[i])
    167             {
    168                 int d = outd[i]-ind[i];
    169                 dinic.AddEdge(s, i, d/2);
    170                 totflow += d/2;
    171             }
    172             else if(ind[i] > outd[i])
    173             {
    174                 int d = ind[i]-outd[i];
    175                 dinic.AddEdge(i, t, d/2);
    176             }
    177         }
    178     return 1;
    179 }
    180 int check()
    181 {
    182     int count = 0;
    183     for(int i = 1; i <= n; i++) if(vis[i] && fa[i] == i) count++;
    184     if(count > 1) return 0;
    185 
    186     int ans = dinic.Maxflow(s, t);
    187     if(ans >= totflow) return 1;
    188     return 0;
    189 }
    190 void rebuild()
    191 {
    192     for(int i = 0; i < dinic.edges.size(); i++)
    193     {
    194         Edge &e = dinic.edges[i];
    195         if(e.cap > 0 && e.from >= 1 && e.from <= n)
    196         {
    197             if(e.flow == 0) addedge(e.from, e.to);
    198             else addedge(e.to, e.from);
    199         }
    200     }
    201 }
    202 void solve()
    203 {
    204     read_case();
    205     if(build())
    206     {
    207         if(!check()) printf("impossible
    ");
    208         else
    209         {
    210             rebuild();
    211             printf("possible
    ");
    212         }
    213     }
    214     else printf("impossible
    ");
    215 }
    216 int main()
    217 {
    218     int T;
    219     scanf("%d",&T);
    220     while(T--)
    221         solve();
    222     return 0;
    223 }
    View Code
  • 相关阅读:
    第二次冲刺每日站立会议10(完结)
    第二次冲刺每日站立会议09
    第二次冲刺每日站立会议08
    找bug
    测试计划
    博客园的意见与建议
    第二次每日站立会议07
    个人总结
    学习进度条(第十六周)
    梦断代码阅读笔记03
  • 原文地址:https://www.cnblogs.com/ACMERY/p/4787177.html
Copyright © 2020-2023  润新知