zoukankan      html  css  js  c++  java
  • [网络流]最大流

    网络流最大流最小割

    题目链接

    就是一道点割。

    先说边割

    边割比较常见。

    最大流

    最大流等于最小割,我懒得证。

    求最大流的思路就是每次尝试找一条从源点到汇点的通路,然后找到这条路上残余流量最小的流量,答案加上这个流量,这条通路上每条边的残余流量减去这个值,反向边加上这个值。

    关于反向边,实际上是一个反悔机制。反向流多少,表示正向已经流了多少。也就是说,如果我们从反向边流了一些流量,就相当于从这条边退回了一部分流量。

    点割

    所谓点割,就是被割掉的不再是边,而是点。思路是将点转化成边。

    如上题:将每个点拆成(i)(i+n)两个点,中间连一条流量为(1)的边,将这条边割掉,就相当于割掉这个点。

    详见代码。

    #include <iostream>
    #include <cstring>
    #include <cstdio>
    #include <queue>
    using namespace std;
    long long read(){
    	long long x = 0; int f = 0; char c = getchar();
    	while(c < '0' || c > '9') f |= c == '-', c = getchar();
    	while(c >= '0' && c <= '9') x = (x << 1) + (x << 3) + (c ^ 48), c = getchar();
    	return f ? -x:x;
    }
    
    const int INF = 2147483647;
    int n, m, s, t;
    struct szh{
    	int nxt, to, w;
    }a[4004];
    int head[203],cnt=1;
    void add(int x, int y, int w){
    	a[++cnt].nxt = head[x], a[cnt].to = y, head[x] = cnt, a[cnt].w = w;
    }
    
    int dis[203];
    bool bfs(){
    	memset(dis, 0, sizeof dis);
    	queue<int> q;
    	q.push(s), dis[s] = 1;
    	while(!q.empty()){
    		int u = q.front();q.pop();
    		for (int i = head[u], v; v = a[i].to, i; i = a[i].nxt)
    			if(a[i].w && !dis[v]) q.push(v), dis[v] = dis[u] + 1;
    	}
    	return dis[t];
    }
    
    int fir[103];
    int dfs(int u, int flow){
    	if(u == t || !flow) return flow;
    	int ans = 0;
    	for (int &i = fir[u], v; v = a[i].to, i; i = a[i].nxt)
            //弧优化
    		if(a[i].w && dis[v] == dis[u] + 1){
    			int x = dfs(v, min(flow, a[i].w));
    			a[i].w -= x, a[i^1].w += x, ans += x; //更新残余流量
    			if(!(flow-=x)) break;
    		}
    	return ans;
    }
    
    void dinic(){
    	int ans = 0;
    	while(bfs()){
    		for (int i = 1; i <= (n << 1); ++i) fir[i] = head[i];
            //为dfs中取址操作做铺垫
    		ans += dfs(s,INF);
    	}
    	printf("%d", ans);
    }
    
    int main(){
    	n = read(), m = read(), s = read(), t = read();
        s += n; //源点不能删掉
    	for (int i = 1; i <= n; ++i) add(i, i + n, 1), add(i + n, i, 0);
        //拆点
    	for (int i = 1; i <= m; ++i){
    		int x = read(), y = read();
    		add(x + n, y, INF), add(y, x + n, 0); //电脑之间不会断,所以连INF
    		add(y + n, x, INF), add(x, y + n, 0);
    	}
    	dinic(); //模板
    	return 0;
    }
    
  • 相关阅读:
    UVALive
    hdu 3869 Color the Simple Cycle (kmp+polya计数)
    zoj 3794 Greedy Driver
    zoj 3795 Grouping
    ASP.NET Core 简介
    ASP.NET Core 基础教程
    iOS ShareSDK Scheme
    微博授权失败 redirect_uri_mismatch
    集成友盟分享SDK报错
    获取设备实际宽度
  • 原文地址:https://www.cnblogs.com/kylinbalck/p/10590252.html
Copyright © 2011-2022 走看看