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

分析参考:

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

(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 = ;
  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 = ; i <= n; i++) G[i].clear();
  32. edges.clear();
  33. }
  34. void ClearFlow ()
  35. {
  36. for(int i = ; i < edges.size(); i++) edges[i].flow = ;
  37. }
  38. void AddEdge(int from, int to, int cap)
  39. {
  40. edges.push_back(Edge (from, to, cap, ));
  41. edges.push_back(Edge (to, from, , ));
  42. m = edges.size();
  43. G[from].push_back(m-);
  44. G[to].push_back(m-);
  45. }
  46. bool BFS()
  47. {
  48. memset(vis, , sizeof(vis));
  49. queue<int> Q;
  50. Q.push(s);
  51. d[s] = ;
  52. vis[s] = ;
  53. while(!Q.empty())
  54. {
  55. int x = Q.front();
  56. Q.pop();
  57. for(int i = ; 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] = ;
  63. d[e.to] = d[x]+;
  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 == ) return a;
  73. int flow = , f;
  74. for(int &i = cur[x]; i < G[x].size(); i++)
  75. {
  76. Edge& e = edges[G[x][i]];
  77. if(d[x] + == d[e.to] && (f = DFS(e.to, min(a, e.cap-e.flow))) > )
  78. {
  79. e.flow += f;
  80. edges[G[x][i]^].flow -= f;
  81. flow += f;
  82. a -= f;
  83. if(a == ) 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 = ;
  93. while(BFS())
  94. {
  95. memset(cur, , 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 = ;
  126. edge[cnt].next = first[u], first[u] = cnt++;
  127. }
  128. void init()
  129. {
  130. cnt = ;
  131. memset(first, -, sizeof(first));
  132. memset(ind, , sizeof(ind));
  133. memset(outd, , sizeof(outd));
  134. memset(vis, , sizeof(vis));
  135. for(int i = ; i <= n+; i++) fa[i] = i;
  136. }
  137. void read_case()
  138. {
  139. scanf("%d%d",&n,&m);
  140. init();
  141. dinic.init(n+);
  142. while(m--)
  143. {
  144. int x, y;
  145. char c;
  146. scanf("%d %d %c", &x, &y, &c);
  147. if(c == '')
  148. addedge(x, y);
  149. else if(c == '')
  150. dinic.AddEdge(x, y, );
  151. vis[x] = vis[y] = ;
  152. outd[x]++, ind[y]++;
  153. Union(x, y);
  154. }
  155. }
  156. int totflow;
  157. int build()
  158. {
  159. s = , t = n+;
  160. totflow = ;
  161. for(int i = ; i <= n; i++)
  162. if(vis[i])
  163. {
  164. if((outd[i]+ind[i]) & )
  165. return ;
  166. else if(outd[i] > ind[i])
  167. {
  168. int d = outd[i]-ind[i];
  169. dinic.AddEdge(s, i, d/);
  170. totflow += d/;
  171. }
  172. else if(ind[i] > outd[i])
  173. {
  174. int d = ind[i]-outd[i];
  175. dinic.AddEdge(i, t, d/);
  176. }
  177. }
  178. return ;
  179. }
  180. int check()
  181. {
  182. int count = ;
  183. for(int i = ; i <= n; i++) if(vis[i] && fa[i] == i) count++;
  184. if(count > ) return ;
  185.  
  186. int ans = dinic.Maxflow(s, t);
  187. if(ans >= totflow) return ;
  188. return ;
  189. }
  190. void rebuild()
  191. {
  192. for(int i = ; i < dinic.edges.size(); i++)
  193. {
  194. Edge &e = dinic.edges[i];
  195. if(e.cap > && e.from >= && e.from <= n)
  196. {
  197. if(e.flow == ) 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\n");
  208. else
  209. {
  210. rebuild();
  211. printf("possible\n");
  212. }
  213. }
  214. else printf("impossible\n");
  215. }
  216. int main()
  217. {
  218. int T;
  219. scanf("%d",&T);
  220. while(T--)
  221. solve();
  222. return ;
  223. }

POJ 1637 混合图的欧拉回路判定的更多相关文章

  1. POJ 1637 混合图求欧拉回路 最大流实现

    前面讲过了无向图,有向图求欧拉回路,欧拉通路的做法.可以直接根据度数来判断,当然前提是这是一个连通图. 这道题既有无向边,又有有向边,然后求欧拉回路. 采用的方法是最大流. 具体处理方法. 首先,我们 ...

  2. [POJ1637]混合图的欧拉回路判定|网络流

    混合图的欧拉回路判定 上一篇正好分别讲了有向图和无向图的欧拉回路判定方法 如果遇上了混合图要怎么做呢? 首先我们思考有向图的判定方法:所有点的出度=入度 我们可以先为无向边任意定一个向,算出此时所有顶 ...

  3. POJ 1637 混合图欧拉回路

    先来复习一下混合图欧拉回路:给定一张含有单向边和双向边的图,使得每一点的入度出度相同. 首先对于有向边来说,它能贡献的入度出度是确定的,我们不予考虑.对于无向图,它可以通过改变方向来改变两端点的出入度 ...

  4. poj 1637 混合图欧拉回路 学习笔记

    题目大意 求混合图是否存在欧拉回路 做法 有向边我们只有增加入度出度 对于无向边,我们给它设定一个初始方向 如果不能满足|入度-出度|为偶数,无解 然后在网络流图中, 设设定方向的反向连一条边,表示反 ...

  5. ACM/ICPC 之 混合图的欧拉回路判定-网络流(POJ1637)

    //网络流判定混合图欧拉回路 //通过网络流使得各点的出入度相同则possible,否则impossible //残留网络的权值为可改变方向的次数,即n个双向边则有n次 //Time:157Ms Me ...

  6. bzoj2095: [Poi2010]Bridges(二分+混合图求欧拉回路)

    传送门 这篇题解讲的真吼->这里 首先我们可以二分一个答案,然后把所有权值小于这个答案的都加入图中 那么问题就转化为一张混合图(既有有向边又有无向边)中是否存在欧拉回路 首先 无向图存在欧拉回路 ...

  7. 紫书 例题 11-13 UVa 10735(混合图的欧拉回路)(最大流)

    这道题写了两个多小时-- 首先讲一下怎么建模 我们的目的是让所有点的出度等于入度 那么我们可以把点分为两部分, 一部分出度大于入度, 一部分入度大于出度 那么显然, 按照书里的思路,将边方向后,就相当 ...

  8. POJ 1637 Sightseeing tour (混合图欧拉路判定)

    Sightseeing tour Time Limit: 1000MS   Memory Limit: 10000K Total Submissions: 6986   Accepted: 2901 ...

  9. POJ1637:Sightseeing tour(混合图的欧拉回路)

    Sightseeing tour Time Limit: 1000MS   Memory Limit: 10000K Total Submissions: 10581   Accepted: 4466 ...

随机推荐

  1. MySQL exists的用法介绍

    有一个查询如下: 1 SELECT c.CustomerId, CompanyName   2 FROM Customers c   3 WHERE EXISTS(   4     SELECT Or ...

  2. WebForm复杂控件

    Calendar   日历: FileUpdate 文件上传: Image 图片,可以直接给URL: Repeater: HeaderTemplate - 在加载开始执行一遍 ItemTemplate ...

  3. Windows Phone 10如何借Windows 10的东风

    距微软发布Windows Phone 7已经四年多了,WinPhone的市场份额一直萎糜不前.去年微软收购诺基亚,如特洛伊木马般戏剧,却没有挽救WinPhone,甚至出现下滑,已经不足3%,已经基本被 ...

  4. 配置 Windows 下的 nodejs C++ 模块编译环境

    根据 node-gyp 指示的 Windows 编译环境说明, 简单一句话就是 "Python + VC++ 编译环境". 所有需要的安装文件, 我都下载好放到百度云盘了: nod ...

  5. 关于MVC4项目从32位机移到64位机编译报错解决方案

    早上写了个MVC WEBAPI的demo 机子环境是:XP SP3+ VS2010 + ASP.NET MVC4 然后晚上拿回笔记本进行编译运行,结果报错如下: “/”应用程序中的服务器错误. 分析器 ...

  6. 16061701(地图灯光编译Beast报错)

    [目标] 地图灯光编译报错 [思路] 1 我自己测c2_cwd_rt 附件为当时log 2 ExampleGame\BeastCache\PersistentCache 3 重新删除掉BeastCac ...

  7. js小时分钟控件--

    直接上代码: var str = ""; document.writeln("<div id=\"_contents\" tabindex=99 ...

  8. HashBytes(Transact-SQL)

    返回其输入的MD2.MD4.MD5.SHA或SHA1哈希值 语法 HashBytes('<algorithm>',{@input|'input'}) <algorithm>:: ...

  9. [版本管理]有惊无险修复svn服务器Invalid filesystem revision number问题

    问题起因:某一天下午,团队成员在向svn服务端提交新内容,突然整栋楼断电了,自然,提交的过程被中断了.当时,还没有什么想法. 等有电后,另外一同事在update项目时,发现无法正常使用svn,一直报异 ...

  10. SQL疑难问题

    最近,遇到并解决一个SQL上的疑难问题.考勤系统,记录着员工进出公司的刷卡记录.而员工刷卡并不规范,存在刷多次的情况.例如:出去时连续刷多次,进来时也连续刷多次.筛选有效刷卡记录数据的规则:对于出去时 ...