zoukankan      html  css  js  c++  java
  • BZOJ 2095 [Poi2010]Bridges (二分+最大流判断混合图的欧拉回路)

    题面

    nn个点,mm条双向边(正向与反向权值不同),求经过最大边权最小的欧拉回路的权值

    分析

    commonc大佬博客

    • 精髓就是通过最大流调整无向边的方向使得所有点的入度等于出度

    CODE

    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    using namespace std;
    template<typename T>inline void read(T &num) {
        char ch; while((ch=getchar())<'0'||ch>'9');
        for(num=0;ch>='0'&&ch<='9';num=num*10+ch-'0',ch=getchar());
    }
    const int inf = 1e9;
    const int MAXN = 1005;
    const int MAXM = 100005;
    int n, m, p, fir[MAXN], S, T, tot, cnt, deg[MAXN];
    struct edge { int to, nxt, c; }e[MAXM];
    inline void add(int u, int v, int cc) {
    	e[cnt] = (edge){ v, fir[u], cc }; fir[u] = cnt++;
    	e[cnt] = (edge){ u, fir[v], 0 }; fir[v] = cnt++;
    }
    int dis[MAXN], vis[MAXN], info[MAXN], cur, q[MAXN];
    inline bool bfs() {
    	int head = 0, tail = 0;
    	vis[S] = ++cur; q[tail++] = S;
    	while(head < tail) {
    		int u = q[head++];
    		for(int i = fir[u]; ~i; i = e[i].nxt)
    			if(e[i].c && vis[e[i].to] != cur)
    				vis[e[i].to] = cur, dis[e[i].to] = dis[u] + 1, q[tail++] = e[i].to;
    	}
    	if(vis[T] == cur) memcpy(info, fir, (T+1)<<2);
    	return vis[T] == cur;
    }
    int dfs(int u, int Max) {
    	if(u == T || !Max) return Max;
    	int flow=0, delta;
    	for(int &i = info[u]; ~i; i = e[i].nxt)
    		if(e[i].c && dis[e[i].to] == dis[u] + 1 && (delta=dfs(e[i].to, min(e[i].c, Max-flow)))) {
    			e[i].c -= delta, e[i^1].c += delta, flow += delta;
    			if(flow == Max) return flow;
    		}
    	return flow;
    }
    inline int dinic() {
    	int flow=0, x;
    	while(bfs()) {
    		while((x=dfs(S, inf))) flow+=x;
    	}
    	return flow;
    }
    int A[2005], B[2005], C[2005], D[2005];
    inline bool check(int mid) {
    	memset(fir, -1, sizeof fir); cnt = 0;
    	for(int i = 1; i <= m; ++i) {
    		if(C[i] > mid) return 0;
    		if(D[i] <= mid)
    			add(A[i], B[i], 1);
    	}
    	int sum = 0;
    	for(int i = 1; i <= n; ++i)
    		if(deg[i] > 0) add(i, T, deg[i]/2);
    		else if(deg[i] < 0) add(S, i, -deg[i]/2), sum -= deg[i]/2;
    	return dinic() == sum;
    }
    int main () {
    	read(n), read(m); S = 0; T = n+1;
    	for(int i = 1; i <= m; ++i) {
    		read(A[i]), read(B[i]), read(C[i]), read(D[i]);
    		if(C[i] > D[i]) swap(A[i], B[i]), swap(C[i], D[i]);
    		--deg[A[i]], ++deg[B[i]];
    	}
    	for(int i = 1; i <= n; ++i)
    		if(deg[i] % 2) return printf("NIE"), 0;
    	int l = 1, r = 1000, mid;
    	while(l < r) {
    		mid = (l + r) >> 1;
    		if(check(mid)) r = mid;
    		else l = mid+1;
    	}
    	printf("%d
    ", l);
    }
    
  • 相关阅读:
    UIView用户事件响应
    登录模块之静态登录
    对C# 中Readonly的再认识
    [Android学习笔记4]四大应用组件之一:Service 上
    修改XPMenu让ToolButton在Down=True时正确显示
    通过程序预览Office文档
    发掘ListBox的潜力(三):显示即时提示(Tips)
    从网络上下载文件的两种方法
    解决窗体闪烁问题的方法
    C/C++中动态链接库的创建和调用
  • 原文地址:https://www.cnblogs.com/Orz-IE/p/12039416.html
Copyright © 2011-2022 走看看