zoukankan      html  css  js  c++  java
  • 「POI2010」Bridges

    传送门
    Luogu团队题链接

    解题思路

    首先二分答案,然后在所有边权小于二分值的边和所有点组成的图中判欧拉回路。
    由于可能出现混合图,所以要用到网络流。
    把所有无向边钦定一个方向,那么原图就是一个有向图。
    那么存在欧拉回路的充要条件就所有点的入度等于出度且图联通。
    我们考虑把点 (x) 的入度与出度之差记作 (Delta x)
    那么对于所有的定向后的无向边 ((u,v)),连一条从 (u ightarrow v) 的容量为 (1) 的边。
    表示将该条边反向可以使 (Delta u += 2,Delta v -= 2)
    然后考虑对于所有度数差小于 (0) 的点 (x),连一条 (s ightarrow x) 的容量为 (frac{|Delta x|}{2}) 的边。
    表示 (x) 需要操作这么多次,使得 (Delta x) 达到 (0)。小于零的情况同理。
    最后判断是否满流即可。

    细节注意事项

    • 细节有点多,要有耐心

    参考代码

    #include <algorithm>
    #include <iostream>
    #include <cstring>
    #include <cstdlib>
    #include <cstdio>
    #include <cctype>
    #include <cmath>
    #include <ctime>
    #include <queue>
    #define rg register
    using namespace std;
    template < typename T > inline void read(T& s) {
    	s = 0; int f = 0; char c = getchar();
    	while (!isdigit(c)) f |= (c == '-'), c = getchar();
    	while (isdigit(c)) s = s * 10 + (c ^ 48), c = getchar();
    	s = f ? -s : s;
    }
    
    const int _ = 1010;
    const int __ = 5010 * 2 + 1010 * 2;
    const int INF = 2147483647;
    
    int tot = 1, head[_], nxt[__], ver[__], cap[__];
    inline void Add_edge(int u, int v, int d)
    { nxt[++tot] = head[u], head[u] = tot, ver[tot] = v, cap[tot] = d; }
    inline void link(int u, int v, int d) { Add_edge(u, v, d), Add_edge(v, u, 0); }
    
    int n, m, s, t, liu, dgr[_], dep[_];
    struct node{ int a, b, c, d; }g[__];
    
    inline int bfs() {
    	static queue < int > Q;
    	memset(dep, 0, sizeof dep);
    	dep[s] = 1, Q.push(s);
    	while (!Q.empty()) {
    		int u = Q.front(); Q.pop();
    		for (rg int i = head[u]; i; i = nxt[i]) {
    			int v = ver[i];
    			if (dep[v] == 0 && cap[i] > 0)
    				dep[v] = dep[u] + 1, Q.push(v);
    		}
    	}
    	return dep[t] > 0;
    }
    
    inline int dfs(int u, int flow) {
    	if (u == t) return flow;
    	for (rg int i = head[u]; i; i = nxt[i]) {
    		int v = ver[i];
    		if (dep[v] == dep[u] + 1 && cap[i] > 0) {
    			int res = dfs(v, min(flow, cap[i]));
    			if (res) { cap[i] -= res, cap[i ^ 1] += res; return res; }
    		}
    	}
    	return 0;
    }
    
    inline int Dinic() {
    	int res = 0;
    	while (bfs()) while (int d = dfs(s, INF)) res += d;
    	return res;
    }
    
    inline bool check(int mid) {
    	s = 0, t = n + 1;
    	tot = 1, memset(head, 0, sizeof head);
    	for (rg int i = 1; i <= m; ++i) {
    		if (g[i].c > mid) return 0;
    		if (g[i].d <= mid) link(g[i].a, g[i].b, 1);
    	}
    	for (rg int i = 1; i <= n; ++i) {
    		if (dgr[i] < 0) link(s, i, -dgr[i] / 2);
    		if (dgr[i] > 0) link(i, t, dgr[i] / 2);
    	}
    	return Dinic() == liu / 2;
    }
    
    int main() {
    #ifndef ONLINE_JUDGE
    	freopen("in.in", "r", stdin);
    #endif
    	read(n), read(m);
    	for (rg int i = 1; i <= m; ++i) {
    		read(g[i].a), read(g[i].b), read(g[i].c), read(g[i].d);
    		if (g[i].c > g[i].d)
    			swap(g[i].a, g[i].b), swap(g[i].c, g[i].d);
    		--dgr[g[i].a], ++dgr[g[i].b];
    	}
    	for (rg int i = 1; i <= n; ++i) {
    		if (dgr[i] % 2 != 0) return puts("NIE"), 0;
    		liu += abs(dgr[i]) / 2;
    	}
    	int l = 1, r = 1000;
    	while (l < r) {
    		int mid = (l + r) >> 1;
    		if (check(mid)) r = mid;
    		else l = mid + 1;
    	}
    	printf("%d
    ", l);
    	return 0;
    }
    

    完结撒花 (qwq)

  • 相关阅读:
    MySQL Execution Plan--合理利用隐式的业务逻辑
    MySQL Table--MySQL外键
    MySQL倒序索引测试2
    MySQL倒序索引测试1
    CCNA-3.硬件介质
    CCNA-2.OSI 7层网络模型
    CCNA-1.认识网络
    windows本地安装Oracle数据库
    扫码登录实现原理
    phpunit 单元测试
  • 原文地址:https://www.cnblogs.com/zsbzsb/p/11745810.html
Copyright © 2011-2022 走看看