BZOJ 2132 圈地计划 最小割

夙愿已清 提交于 2019-12-02 23:32:49

 

 首先黑白染色 因为相邻的节点颜色必不同 相同颜色的节点之间没有关系(没有边)

然后Add(S,黑色点,A[i][j]) (黑色点,T,B[i][j])(S,白色点,B[i][j])(白色点,T,A[i][j])因为黑色点和白色点同属一个S/T才有额外贡献 所以这里A[i][j],B[i][j]要交换连

sum初始为矩阵里每个点的A,B之和 对于每个点 向它四周相邻的点连(u,v,C[i][j]+C[i'][j']) 注意这里黑色到白色 白色到黑色都要连 因为有属于S/T两种情况

然后一个点有X个相邻点则sum+=X*C[i][j] 因为上面连的C[i][j]+C[i'][j']容量的边其实有两条但是却不存在同时切两条的情况 最多只会切一条

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef int JQK;
int n, m;
namespace dinic {
        const int MAXN = 10050;
        const int MAXM = 100050;
        const int INF = 1000000050;
        int Head[MAXN], cur[MAXN], lev[MAXN], to[MAXM << 1], nxt[MAXM << 1], ed = 1;
        int S, T, MAXP;
        JQK f[MAXM << 1];
        inline void addedge(int u, int v, JQK cap) {
                to[++ed] = v;
                nxt[ed] = Head[u];
                Head[u] = ed;
                f[ed] = cap;
                to[++ed] = u;
                nxt[ed] = Head[v];
                Head[v] = ed;
                f[ed] = 0;
                return;
        }
        inline bool BFS() {
                int u;
                for (int i = 0; i <= MAXP + 1; i++) {
                        lev[i] = -1;
                }
                //memset(lev, -1, sizeof(lev));
                queue<int>q;
                lev[S] = 0;
                q.push(S);
                while (q.size()) {
                        u = q.front();
                        q.pop();
                        for (int i = Head[u]; i; i = nxt[i])
                                if (f[i] && lev[to[i]] == -1) {
                                        lev[to[i]] = lev[u] + 1;
                                        q.push(to[i]);
                                        /*
                                        if (to[i] == T)
                                        {
                                                return 1;
                                        }
                                        magic one way optimize
                                        */
                                }
                }
                for (int i = 0; i <= MAXP + 1; i++) {
                        cur[i] = Head[i];
                }
                //memcpy(cur, Head, sizeof Head);
                return lev[T] != -1;
        }
        JQK DFS(int u, JQK maxf) {
                if (u == T || !maxf) {
                        return maxf;
                }
                JQK cnt = 0, tem;
                for (int &i = cur[u]; i; i = nxt[i])
                        if (f[i] && lev[to[i]] == lev[u] + 1) {
                                tem = DFS(to[i], min(maxf, f[i]));
                                maxf -= tem;
                                f[i] -= tem;
                                f[i ^ 1] += tem;
                                cnt += tem;
                                if (!maxf) {
                                        break;
                                }
                        }
                if (!cnt) {
                        lev[u] = -1;
                }
                return cnt;
        }
        JQK Dinic() {
                JQK ans = 0;
                while (BFS()) {
                        ans += DFS(S, INF);
                }
                return ans;
        }
        void init(int SS, int TT) {
                for (int i = 0; i <= MAXP + 1; i++) {
                        Head[i] = 0;
                }
                ed = 1;
                S = SS;
                T = TT;
                return;
        }
        int work() {
                return Dinic();
        }
}
int dir[4][2] = {{0, 1}, {1, 0}, {0, -1}, { -1, 0}};
int bl[105][105];
int sum = 0;
int A[105][105], B[105][105], C[105][105];
int main() {
        int n, m;
        scanf("%d %d", &n, &m);
        dinic::MAXP = n * m + 5;
        int s, t;
        s = n * m + 1, t = s + 1;
        dinic::init(s, t);
        for (int i = 1; i <= n; i++)
                for (int j = 1; j <= m; j++) {
                        scanf("%d", &A[i][j]);
                        sum += A[i][j];
                }
        for (int i = 1; i <= n; i++)
                for (int j = 1; j <= m; j++) {
                        scanf("%d", &B[i][j]);
                        sum += B[i][j];
                }
        for (int i = 1; i <= n; i++)
                for (int j = 1; j <= m; j++) {
                        scanf("%d", &C[i][j]);
                }
        for (int i = 1; i <= n; i++) {
                for (int j = 1; j <= m; j++) {
                        bl[i][j] = (i + j) % 2;
                        int now = (i - 1) * m + j;
                        if (bl[i][j]) {
                                dinic::addedge(s, now, A[i][j]), dinic::addedge(now, t, B[i][j]);
                        } else {
                                dinic::addedge(s, now, B[i][j]), dinic::addedge(now, t, A[i][j]);
                        }
                        for (int k = 0; k < 4; k++) {
                                int dx = i + dir[k][0];
                                int dy = j + dir[k][1];
                                if (dx >= 1 && dx <= n && dy >= 1 && dy <= m) {
                                        int aim = (dx - 1) * m + dy;
                                        sum += C[i][j];
                                        dinic::addedge(now, aim, C[i][j] + C[dx][dy]);
                                }
                        }
                }
        }
        printf("%d\n", sum - dinic::Dinic());
        return 0;
}

 

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!