zoukankan      html  css  js  c++  java
  • [题解] [JSOI2015] 圈地

    题面

    题解

    发现一种地要么归 (A) , 要么归 (B) , 若相邻两块归属不同还有额外代价

    那么 (A) 买就连源点, (B) 买就连汇点

    总收益加上这些值

    中间连代价的双向边

    答案为总收益减去最小割

    Code

    #include <algorithm>
    #include <iostream>
    #include <cstring>
    #include <cstdio>
    #include <queue>
    #include <cmath>
    const int N = 160005; 
    const int INF = 0x3f3f3f3f; 
    using namespace std; 
    
    int n, m, id[405][405], head[N], S, T, cnte = 1, d[N], cur[N], ans; 
    struct edge { int to, nxt, flow; } e[N << 4]; 
    queue<int> q; 
    
    template < typename T >
    inline T read()
    {
        T x = 0, w = 1; char c = getchar(); 
        while(c < '0' || c > '9') { if(c == '-') w = -1; c = getchar(); }
        while(c >= '0' && c <= '9') x = x * 10 + c - '0', c = getchar(); 
        return x * w;   
    }
    
    inline void adde(int u, int v, int w)
    {
        e[++cnte] = (edge) { v, head[u], w }, head[u] = cnte;
        e[++cnte] = (edge) { u, head[v], 0 }, head[v] = cnte; 
    }
    
    bool bfs()
    {
        memset(d, 0, sizeof(d)), d[S] = 1, q.push(S); 
        while(!q.empty())
        {
    	int u = q.front(); q.pop();
    	for(int v, i = head[u]; i; i = e[i].nxt)
    	{
    	    v = e[i].to; 
    	    if(e[i].flow > 0 && !d[v])
    		d[v] = d[u] + 1, q.push(v); 
    	}
        }
        return d[T]; 
    }
    
    int dfs(int u, int a)
    {
        if(u == T || !a) return a;
        int f = 0;
        for(int v, i = head[u]; i; i = e[i].nxt)
        {
    	v = e[i].to; 
    	if(e[i].flow > 0 && d[v] == d[u] + 1)
    	{
    	    int tmp = dfs(v, min(a, e[i].flow)); 
    	    a -= tmp, f += tmp, e[i].flow -= tmp, e[i ^ 1].flow += tmp; 
    	}
    	if(!a) break; 
        }
        if(a) d[u] = 0;
        return f; 
    }
    
    int dinic()
    {
        int flow = 0;
        while(bfs())
    	flow += dfs(S, INF); 
        return flow; 
    }
    
    int main()
    {
        n = read <int> (), m = read <int> (), S = n * m + 1, T = S + 1; 
        for(int x, i = 1; i <= n; i++)
            for(int j = 1; j <= m; j++)
            {
                id[i][j] = (i - 1) * m + j, x = read <int> (); 
    	    if(x >= 0) adde(S, id[i][j], x); 
                else adde(id[i][j], T, -x); 
                ans += (x > 0 ? x : -x); 
            }
        for(int x, i = 1; i < n; i++)
            for(int j = 1; j <= m; j++)
            {
                x = read <int> (); 
                adde(id[i][j], id[i + 1][j], x);
    	    adde(id[i + 1][j], id[i][j], x); 
            }
        for(int x, i = 1; i <= n; i++)
            for(int j = 1; j < m; j++)
            {
                x = read <int> (); 
                adde(id[i][j], id[i][j + 1], x);
    	    adde(id[i][j + 1], id[i][j], x); 
            }
        ans -= dinic(); 
        printf("%d
    ", ans); 
        return 0;
    }
    
  • 相关阅读:
    RunLoop学习总结
    单例模式探索
    HTTPS的学习总结
    Objective-C 链式编程思想
    iOS开发之计算动态cell的高度并缓存
    iOS开发之SDWebImage详解
    HDU 1211 RSA(快速幂)
    HDU 4965 Fast Matrix Calculation (矩阵快速幂)
    POJ 3233 Matrix Power Series(矩阵快速幂+二分求和)
    POJ 3518 (筛素数)
  • 原文地址:https://www.cnblogs.com/ztlztl/p/12358743.html
Copyright © 2011-2022 走看看