传送门:http://www.lydsy.com:808/JudgeOnline/problem.php?id=2127

第3道最小割!!!分析我就不说了,网上到处都是。刷了三道最小割,终于更深刻的理解了根据不同方案的分析来确定边的流量233。。。

#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
#define INF 0x3f3f3f3f
const int maxn = 10010, maxm = 1000010, maxk = 110;
int fir[maxn], edge[maxm], next[maxm], cap[maxm];
int d[maxn], vd[maxn];
int num[maxk][maxk];
int dd[4][2] = {{1, 0}, {0, 1}, {-1, 0}, {0, -1}};
int n, m, ans, s, t, cnt, tot;
void addedge(int a, int b, int f) {
    edge[cnt] = b; next[cnt] = fir[a]; fir[a] = cnt; cap[cnt ++] = f;
    edge[cnt] = a; next[cnt] = fir[b]; fir[b] = cnt; cap[cnt ++] = 0;
    return;
}
int Isap(int r, int aflow) {
    if(r == t) return aflow;
    int flow = aflow, f, md = t - 1;
    for(int i = fir[r]; ~i ; i = next[i]) {
        int v = edge[i];
        if(cap[i]) {
            if(d[r] == d[v] + 1) {
                f = min(flow, cap[i]);
                f = Isap(v, f);
                cap[i] -= f;
                cap[i ^ 1] += f;
                flow -= f;
                if(d[s] >= t) return aflow - flow;
                if(!flow) break;
            }
            md = min(md, d[v]);
        }
    }
    if(flow == aflow) {
        vd[d[r]] --;
        if(!vd[d[r]]) d[s] = t;
        d[r] = md + 1;
        vd[d[r]] ++;
    }
    return aflow - flow;
}
int main() {
    memset(fir, -1, sizeof(fir));
    scanf("%d%d", &n, &m);
    for(int i = 1; i <= n; i ++) {
        for(int j = 1; j <= m; j ++) {
            num[i][j] = ++tot;
        }
    }
    s = tot + 1; t = tot + 2;
    int v;
    for(int i = 1; i <= n; i ++) {
        for(int j = 1; j <= m; j ++) {
            scanf("%d", &v);
            ans += v * 2;
            addedge(s, num[i][j], v * 2);
        }
    }
    for(int i = 1; i <= n; i ++) {
        for(int j = 1; j <= m; j ++) {
            scanf("%d", &v);
            ans += v * 2;
            addedge(num[i][j], t, v * 2);
        }
    }
    for(int i = 1; i < n; i ++) {
        for(int j = 1; j <= m; j ++) {
            scanf("%d", &v);
            ans += v * 2;
            addedge(s, num[i][j], v);
            addedge(s, num[i + 1][j], v);
            addedge(num[i][j], num[i + 1][j], v);
            addedge(num[i + 1][j], num[i][j], v);
        }
    }
    for(int i = 1; i < n; i ++) {
        for(int j = 1; j <= m; j ++) {
            scanf("%d", &v);
            ans += v * 2;
            addedge(num[i][j], t, v);
            addedge(num[i + 1][j], t, v);
            addedge(num[i][j], num[i + 1][j], v);
            addedge(num[i + 1][j], num[i][j], v);
        }
    }
    for(int i = 1; i <= n; i ++) {
        for(int j = 1; j < m; j ++) {
            scanf("%d", &v);
            ans += v * 2;
            addedge(s, num[i][j], v);
            addedge(s, num[i][j + 1], v);
            addedge(num[i][j], num[i][j + 1], v);
            addedge(num[i][j + 1], num[i][j], v);
        }
    }
    for(int i = 1; i <= n; i ++) {
        for(int j = 1; j < m; j ++) {
            scanf("%d", &v);
            ans += v * 2;
            addedge(num[i][j], t, v);
            addedge(num[i][j + 1], t, v);
            addedge(num[i][j], num[i][j + 1], v);
            addedge(num[i][j + 1], num[i][j], v);
        }
    }
    vd[0] = t;
    while(d[s] < t) ans -= Isap(s, INF);
    printf("%d\n", ans / 2);
    return 0;
}