网络流24题(09)方格取数问题(最大点权独立集 + 最小割最大流)

题意:

在一个有 m*n 个方格的棋盘中,每个方格中有一个正整数。现要从方格中取数,使任意 2 个数所在方格没有公共边,且取出的数的总和最大。

思路:

1. 不清楚何为“最小点权覆盖集”和“最大点权独立集”概念的请看这篇文章《最小割模型在信息学竞赛中的应用》;

2. “最小点权覆盖集”和“最大点权独立集”是两个互补的概念,我们可以利用最小割求一个二分图的最小点权覆盖集;

3. 把黑白相间染色,黑色部分为 X 集,白色部分为 Y 集,s 向 X 中的点引弧, Y 向 t 引弧,容量为 点权的大小;

   X 和 Y 中相邻的点由 X 向 Y 引弧,容量为无穷大,这么做的目的是为了让割边仅在 <s, X> 或 <Y, t> 中;

4. 之所以这么做,是因为我们要求这个图中的“最大点权独立集”,依照其概念可以知道:任意两点不相邻<=>任意两点构成的边不在图中;

5. 求上面网络的最大流,并且根据最小割最大流定理,再根据我们的建图,最大流->最小割->最小点权覆盖。输出 = 总点权 - 最大流;

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <queue>
#include <vector>
using namespace std;

const int MAXN = 50*50;
const int INFS = 0x7FFFFFFF;

struct edge {
    int from, to, cap, flow;
    edge(int _from, int _to, int _cap, int _flow) 
        : from(_from), to(_to), cap(_cap), flow(_flow) {}
};

class Dinic {
public:
    void initdata(int n, int s, int t) {
        this->n = n, this->s = s, this->t = t;
        edges.clear();
        for (int i = 0; i < n; i++)
            G[i].clear();
    }
    void addedge(int u, int v, int cap) {
        edges.push_back(edge(u, v, cap, 0));
        edges.push_back(edge(v, u, 0, 0));
        G[u].push_back(edges.size() - 2);
        G[v].push_back(edges.size() - 1);
    }
    bool BFS() {
        for (int i = 0; i < n; i++)
            vis[i] = false, d[i] = 0;
        queue<int> Q;
        Q.push(s);
        vis[s] = true;
        while (!Q.empty()) {
            int x = Q.front(); Q.pop();
            for (int i = 0; i < G[x].size(); i++) {
                edge& e = edges[G[x][i]];
                if (e.cap > e.flow && !vis[e.to]) {
                    vis[e.to] = true;
                    d[e.to] = d[x] + 1;
                    Q.push(e.to);
                }
            }
        }
        return vis[t];
    }
    int DFS(int x, int aug) {
        if (x == t || aug == 0) return aug;
        int flow = 0;
        for (int i = 0; i < G[x].size(); i++) {
            edge& e = edges[G[x][i]];
            if (d[e.to] == d[x] + 1) {
                int f = DFS(e.to, min(aug, e.cap - e.flow));
                if (f <= 0) continue;
                e.flow += f;
                edges[G[x][i]^1].flow -= f;
                flow += f;
                aug -= f;
                if (aug == 0) break;
            } 
        }
        return flow;
    }
    int maxflow() {
        int flow = 0;
        while (BFS()) {
            flow += DFS(s, INFS);
        }
        return flow;
    }
private:
    vector<edge> edges;
    vector<int> G[MAXN];
    int n, s, t, d[MAXN];
    bool vis[MAXN];
};

Dinic dc;
int row, col;
int dir[4][2] = {1, 0, -1, 0, 0, 1, 0, -1};

bool check(int x, int y) {
    if (1 <= x && x <= row && 1 <= y && y <= col) {
        return true;
    }
    return false;
}

int main() {
    scanf("%d%d", &row, &col);
    int sum = 0;
    int s = 0, t = row*col + 1;
    dc.initdata(t + 1, s, t);
    for (int i = 1; i <= row; i++) {
        for (int j = 1; j <= col; j++) {
            int a;
            scanf("%d", &a);
            sum += a;
            if ((i+j) & 1)
                dc.addedge((i-1)*col+j, t, a);
            else {
                dc.addedge(s, (i-1)*col+j, a);
                for (int k = 0; k < 4; k++) {
                    int x = i + dir[k][0];
                    int y = j + dir[k][1];
                    if (check(x, y))
                        dc.addedge((i-1)*col+j, (x-1)*col+y, INFS);
                }
            }
        }
    }
    printf("%d\n", sum - dc.maxflow());
    return 0;
}
原文地址:https://www.cnblogs.com/kedebug/p/3033183.html