题意

(混合图的欧拉回路判定)

给你一个既存在有向边, 又存在无向边的图. 问是否存在欧拉回路.

\(N ≤ 200, M ≤ 1000\)

题解

难点在于无向边. 考虑每个点的度数限制.

我们先对无向边任意定向, 现在每个点都有一个出度和入度的差; 而我们要求最终每个点出度和入度相等.

令它出度减去入度为 \(deg​\) ,如果 \(deg​\) 为奇数那么必不存在欧拉回路,因为每次我们修改一条边的定向,会使得入度 \(+1​\) 出度 \(-1​\) (或者相反)。那么变化后的 \(deg​\) 总为奇数,就绝不可能成为 \(0​\) 了。

然后接下来我们就需要判定之后改变边的定向能否满足要求。因为范围较小,我们继续可以联想到网络流。

首先我们建出超级源 \(S\) 、超级汇 \(T\) 。

  1. 把超级源向所有 \(deg > 0\) 的点 \(p\) 连上 \(S \to p\) 流量为 \(\displaystyle \frac{deg}{2}\) 的边。
  2. 把所有 \(deg < 0\) 的点 \(p\) 向超级汇连上 \(p \to T\) 流量为 \(- \displaystyle \frac{deg}{2}\) 的边。
  3. 把原图中存在的无向边我们连上 \(u \to v\) 流量为 \(1\) 的边。注意此处连 \(u \to v\) 的话,需要一开始假设最初的定向就是 \(u \to v\) 使得 ++ deg[u], -- deg[v];

然后跑一遍网络流得到的流量如果和所有 \(deg > 0\) 的点的 \(deg\) 和相同,那么就是存在一组解的,否则就必不存在。

考虑为什么是这样的,因为我们每次流一条边,相当于把一条边 \(u \to v\) 反向成 \(v \to u\) ,使得给 \(u\) 的入度增加 \(1\) 出度减少 \(1\) ,所以 \(deg\) 会直接减少 \(2\) ,这就是为什么我们一开始流量为 \(\displaystyle |\frac{deg}{2}|\) 的原因。

如果满流的结果刚好是 \(\displaystyle\sum_{deg> 0} deg\) ,意味着所有点都修改正确了。

总结

对于有向图欧拉回路的题,牢记 入度 \(=\) 出度 才存在的性质。

代码

#include<cstdio>
#include<iostream>
#include<queue>
#include<cstdlib>
#include<cstring> #define For(i, l, r) for(register int i = (l), i##end = (int)(r); i <= i##end; ++i)
#define Fordown(i, r, l) for(register int i = (r), i##end = (int)(l); i >= i##end; --i)
#define Set(a, v) memset(a, v, sizeof(a))
#define Cpy(a, b) memcpy(a, b, sizeof(a))
#define debug(x) cout << #x << ": " << x << endl
#define DEBUG(...) fprintf(stderr, __VA_ARGS__) using namespace std; inline bool chkmin(int &a, int b) {return b < a ? a = b, 1 : 0;}
inline bool chkmax(int &a, int b) {return b > a ? a = b, 1 : 0;} inline int read() {
int x = 0, fh = 1; char ch = getchar();
for (; !isdigit(ch); ch = getchar()) if (ch == '-') fh = -1;
for (; isdigit(ch); ch = getchar()) x = (x << 1) + (x << 3) + (ch ^ 48);
return x * fh;
} void File() {
#ifdef zjp_shadow
freopen ("1637.in", "r", stdin);
freopen ("1637.out", "w", stdout);
#endif
} int n, m; const int N = 410, M = 5010, inf = 0x7f7f7f7f; namespace Dinic { int Head[N], Next[M], to[M], cap[M], e = 1; inline void add_edge(int u, int v, int flow) { to[++ e] = v; Next[e] = Head[u]; Head[u] = e; cap[e] = flow; } inline void Add(int u, int v, int flow) { add_edge(u, v, flow); add_edge(v, u, 0); } int dis[N], S, T; bool Bfs() {
queue<int> Q; Set(dis, 0); dis[S] = 1; Q.push(S);
while (!Q.empty()) {
int u = Q.front(); Q.pop();
if (u == T) return true;
for (int i = Head[u]; i; i = Next[i]) if (cap[i]) {
int v = to[i];
if (!dis[v]) dis[v] = dis[u] + 1, Q.push(v);
}
}
return false;
} int cur[N];
int Dfs(int u, int flow) {
if (u == T || !flow) return flow;
int res = 0, f;
for (int &i = cur[u]; i; i = Next[i]) if (cap[i]) {
int v = to[i]; if (dis[v] != dis[u] + 1) continue ;
if ((f = Dfs(v, min(flow, cap[i])))) {
cap[i] -= f; cap[i ^ 1] += f;
res += f; if (!(flow -= f)) break;
}
}
if (!res || !flow) dis[u] = 0;
return res;
} int Run() {
int sum_flow = 0;
while (Bfs()) Cpy(cur, Head), sum_flow += Dfs(S, inf);
return sum_flow;
} } using namespace Dinic; int deg[N]; inline bool IsOdd() { For (i, 1, n) if (deg[i] & 1) return true; return false; } int main () { File(); for (int cases = read(); cases; -- cases) { n = read(); m = read(); e = 1;
For (i, 1, n + 2) Head[i] = deg[i] = 0; For (i, 1, m) {
int u = read(), v = read(), type = read();
++ deg[u]; -- deg[v];
if (!type) Add(u, v, 1);
} if (IsOdd()) { puts("impossible"); continue ; } S = n + 1, T = S + 1; int tot = 0;
For (i, 1, n) {
if (deg[i] > 0) Add(S, i, deg[i] >> 1), tot += deg[i] >> 1;
if (deg[i] < 0) Add(i, T, (- deg[i]) >> 1);
}
puts(Run() == tot ? "possible" : "impossible"); } return 0;
}

最新文章

  1. ob_start()
  2. android init进程分析 ueventd
  3. Visual Studio 2015 Update 3 正式版下载
  4. java接口和抽象类
  5. 将自己写的windows服务加入到windows集群中
  6. (转载)web测试方法总结
  7. 深入理解C语言中的指针与数组之指针篇
  8. css 背景色渐变---和背景色透明
  9. DJANGO问题--Error: ‘ManyRelatedManager’ object is not iterable
  10. App如何选择移动广告平台的开发者3 - 选择标准广告平台
  11. socke编程
  12. windows驱动开发前导知识
  13. 最小割求法&amp;&amp;可行边和必须边
  14. Spring Boot 之 Hello World 战记
  15. Samba服务器的配置与使用
  16. shell习题第9题:sed的常用用法
  17. Anaconda 安装 pydot 绘制树状图
  18. ASP.NET MVC之Html.RenderAction(无操作方法 传参数)
  19. 如何优雅地使用win10的Linux子系统
  20. Delphi 转圈 原型进度条 AniIndicator 及线程配合使用

热门文章

  1. 1171: lfx捧杯稳啦!
  2. JSP页面的基本元素
  3. p67交换幺环为整环的充要条件
  4. redis的应用场景 为什么用redis
  5. 在IDEA中配置Spring的XML装配
  6. MyBatis使用注解开发
  7. 【学习总结】win7下安装Ubuntu双系统的日常
  8. vue处理异步数据踩过的坑
  9. scoketio
  10. JS 验证输入框输入 只允许输入正实数(正整数,正小数),其他情况下不能输入 oninput事件