• [POJ 1637] Sightseeing tour(网络流)


    题意

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

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

    (N ≤ 200, M ≤ 1000)

    题解

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

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

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

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

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

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

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

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

    如果满流的结果刚好是 (displaystylesum_{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;
    }
    
  • 相关阅读:
    python 面向对象之路(1) 类和对象 三大特性 封装 继承 多态
    python 模块之路 异常处理基础 异常处理其他 报错处理
    python 模块之路 序列化 json pickle
    python 模块之路 random模块 时间模块 sys模块 os模块
    python 模块之路 re模块运用
    python -模块之路 正则表达式
    【Unity】粒子特效优化实践
    快速实现Low Poly地形
    【Unity】屏幕空间位置变换到世界空间位置的方法
    Substance Designer 使用手册
  • 原文地址:https://www.cnblogs.com/zjp-shadow/p/9568078.html
Copyright © 2020-2023  润新知