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\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 0; 223 }
View Code
转载于:https://www.cnblogs.com/ACMERY/p/4787177.html
POJ 1637 混合图的欧拉回路判定相关推荐
- POJ 1637 混合图的欧拉回路 + Dinic
题意 传送门 POJ 1637 题解 有向图存在欧拉回路的充要条件: 所有顶点入度等于出度,且图为连通图. 混合图存在欧拉回路的判断的基本思路: 混合图 G(V,E)G(V,E)G(V,E) 通过假设 ...
- poj 1637(混合图求欧拉回路)
参考博客:http://www.cnblogs.com/destinydesigner/archive/2009/09/28/1575674.html 1 定义 欧拉通路 (Euler tour)-- ...
- 欧拉回路(混合图的欧拉回路)
/* ID: linjd821 LANG: C++ TASK: sightseeing */ //zju 1992 //混合图的欧拉回路,用网络流调整无向边 /* //转自某位牛人blog 混合图欧拉 ...
- poj1637(混合图判欧拉回路)
把该图的无向边随便定向,计算每个点的入度和出度.如果有某个点出入度 之差为奇数,那么肯定不存在欧拉回路.因为欧拉回路要求每点入度 = 出度, 也就是总度数为偶数,存在奇数度点必不能有欧拉回路. 好了 ...
- Bzoj2095:[Poi2010]Bridges:混合图欧拉回路,网络流
题目链接:2095:[Poi2010]Bridges 二分答案建图后显然是混合图的欧拉回路,有向边删掉无向边随机定向计算入度-出度的差du[i],如果du[i]<0连边(i,T,-du[i]/2 ...
- POJ 1637 Sightseeing tour 混合图欧拉回路存在性判断
没有想到网络流还能解决这一类问题,完全想不到@_@ 一开始把所有的无向边制定任意方向有当做有向边看,然后统计每个点的入度和出度.以前有向图的欧拉回路判定是每个点的入读都等于出度,这样可以保证可以回到起 ...
- poj 1637 Sightseeing tour 混合欧拉图判定
POJ - 1637点我点我:-) Sightseeing tour Time Limit: 1000MS Memory Limit: 10000KB 64bit IO Format: %ll ...
- 混合图的欧拉路径和欧拉回路判断
混合图(既有有向边又有无向边的图)中欧拉环.欧拉路径的判定需要借助网络流!(1)欧拉环的判定: 一开始当然是判断原图的基图是否连通,若不连通则一定不存在欧拉环或欧拉路径(不考虑度数为0的点).其实,难 ...
- 2095: [Poi2010]Bridges 二分+混合图欧拉回路(网络流)
好厉害的题啊QAQ,并不会做. 最大值最小想到是二分,然后就是一个混合图欧拉回路的问题. 混合图欧拉回路问题的解决: 我们首先想到有向图的欧拉回路,需满足的条件是每个点的入度等于出度.那么对于一个混合 ...
最新文章
- 最老程序员创业札记:全文检索、数据挖掘、推荐引擎应用50
- caffe-win10-cifar10另
- 两次深度debug经历,希望大家不要踩坑
- Java EE 8的前5个新功能
- 修改innodb_flush_log_at_trx_commit参数提升insert性能
- java的input不能更改,无法将方法响应标头Content-Type更改为application / xml
- VS Code的golang开发配置 之 代码提示
- vue父子组件的传值
- 操作系统课程设计(页面置换算法 C语言)
- 【招聘测评题】中的(行测)图形推理题基本逻辑总结(附例题)
- java前后端分离跨域解决方案
- 计算机cmd测试,电脑cmd命令怎么测试网速详细步骤
- opc ua与opc da区别_OPC,OPCDA,OPCUA
- 白鹤芋一帆风顺花怎么养 一帆风顺花养殖方法及注意事项
- 算法分析之大O、大Ω、大Θ和小o表示法
- SylixOS软件开发-基础操作
- swing可视化编程-使用label添加图片
- python技能书测评
- android4.0.3 编译lichee 报错dhd-cdc-sdmmc-gpl-3.0.8问题
- java开源项目之IQQ学习记录之项目环境搭建与启动
热门文章
- 网页打印总是提示安装java_使用打印机打印网页时出现的脚本错误的办法
- 拼团商城高保真小程序Axure原型模板
- 自学Vue之路——Vue介绍及基本语法
- 【Java编程练习】司机肇事后逃跑,现场三人半瞎系列
- 【Deep Learning】Transformers Assemble(PART I)
- to_char和to_date的区别
- SpringBoot+JPA 项目启动失败,无法扫描到Repository
- html dashed显示实线怎么改,实现css虚线样式的两种方式:dotted和dashed(实例)
- MTTF,MTBF,MTRF的概念
- LSTM和GRU的对比和分析