[题解] [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\n", ans); 
    return 0;
}
posted @ 2020-02-24 20:54  ztlztl  阅读(119)  评论(0编辑  收藏  举报