zoukankan      html  css  js  c++  java
  • BZOJ 2521: [Shoi2010]最小生成树(最小割)

    题意

    对于某一条无向图中的指定边 ((a, b)) , 求出至少需要多少次操作。可以保证 ((a, b)) 边在这个无向图的最小生成树中.

    一次操作指: 先选择一条图中的边 ((u, v)), 再把图中除了这条边以外的边, 每一条的权值都减少 (1) .

    (n le 500, m le 800, 1 le w_i < 10^6)

    题解

    给除了一条边的所有边权 (-1) ,相当于给这条边的边权 (+1)

    利用生成树的结论,一条边 (u o v) (权值 (w) )若要必定存在于生成树中,那么 (u o v) 所有路径上存在一条边的边权都不能大于 (w)

    那么我们令这些边的权值为 (w_i' = max {w(a,b)-w_i+1, 0})

    然后从 (a o b) 跑一遍最小割就行了。

    这样为什么是对的呢?因为只要割掉了所有可行的边,那么就把 (a, b) 分成两个连通子图,要连上这两个子图的最小代价就是这个最小割的答案。

    总结

    对于一些奇怪数据范围的题,可以向网络流上想。

    代码

    注意连边的时候,需要把正向边和反向边的流量都置为正,这是因为整个图是无向的。

    #include <bits/stdc++.h>
    
    #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 ("2521.in", "r", stdin);
    	freopen ("2521.out", "w", stdout);
    #endif
    }
    
    const int N = 510, M = 810 * 2, inf = 0x3f3f3f3f;
    
    int n, m, id;
    
    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, flow); }
    
    	int S, T, dis[N];
    	bool Bfs() {
    		queue<int> Q; Set(dis, 0); Q.push(S); dis[S] = 1;
    		while (!Q.empty()) {
    			int u = Q.front(); Q.pop();
    			for (int i = Head[u]; i; i = Next[i]) if (cap[i]) {
    				int v = to[i]; if (!dis[v]) { dis[v] = dis[u] + 1; if (v == T) return true; 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 (!flow || !res) 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;
    
    struct Edge { int u, v, w; } lt[M];
    
    int main () {
    
    	File();
    
    	n = read(); m = read(); id = read();
    	For (i, 1, m) {
    		int u = read(), v = read(), w = read();
    		lt[i] = (Edge){u, v, w};
    	}
    	
    	S = lt[id].u; T = lt[id].v;
    	For (i, 1, m) if (id != i) {
    		int res = max(lt[id].w - lt[i].w + 1, 0);
    		if (res) Add(lt[i].u, lt[i].v, res);
    	}
    
    	printf ("%d
    ", Run());
    
        return 0;
    }
    
  • 相关阅读:
    Servlet3.0之五:servlet3.0下的web.xml
    RESTLET开发实例(二)使用Component、Application的REST服务
    并发容器之ConcurrentLinkedDeque
    script的onerror事件支持情况调查
    纯CSS后台框架
    浏览器对width与height的最大值限制
    DOM系统中的各种队列
    跨域的异步请求四
    JSON parse在各浏览器的兼容性列表
    在IE6~8下创建HTML5新标签
  • 原文地址:https://www.cnblogs.com/zjp-shadow/p/9556688.html
Copyright © 2011-2022 走看看