• 【网络流24题】 9. 方格取数问题 题解


    题目链接(洛谷 P2774)

    题意

    有一个(m)(n)列的方格图,每个方格中都有一个正整数。现要从方格中取数,使任意两个数所在方格没有公共边,且取出的数的总和最大,请求出最大的和。

    思路

    显然,这是一个选A就不能选B的那种题。网络流本身就很适合解决这种问题。网络流表示互斥的一种常用方法——在互斥的两个点之间连一条边。这样,我们有了基本的思路。

    然后,我们还要考虑连源点和汇点。我们显然不能让所有的点都连上源点和汇点,那样的话网络流就没有意义了。所以,我们可以考虑拆点,把点(i)拆成((x_i, y_i))。然后,我们把源点向所有(x_i)连一条容量为该点大小的边,从所有(y_i)向汇点连一条容量为(i)点点权的边。

    对于上面说到的连边,我们把互斥的点连边改成——若(i)(j)互斥,则在(x_i)(y_j)之间连一条容量为(INF)的边。

    然后,我们考虑它的含义:如果某一条(组)边的流量跑满了,它的含义是什么?

    一组边指的是,如果(x_1 ightarrow y_2, x_1 ightarrow y_3, x_2 ightarrow y_3),那么称(1,2,3)为一组点,它们之间相互连接的边成为一组边)

    显然是,如果这一组的一些边跑满了,另一些边没跑满,那么显然,根据边容量的含义,我们选择没跑满的那些要更优。所以,我们选择舍弃掉跑满的边要更优。这显然就是最小割。所以,我们用所有点的和减去最小割就是答案了。

    代码

    /**
     * luogu P2774 https://www.luogu.com.cn/problem/P2774
     **/
    
    #include <cstdio>
    #include <algorithm>
    #include <cstring>
    #include <queue>
    
    using namespace std;
    const int maxn = 5e4 + 5;
    const int maxm = 2e5 + 5;
    const int S = 0;
    const int T = maxn - 1;
    const int INF = 0x3f5f5f5f;
    
    struct Edge {
        int to, nxt, val;
    }e[maxm];
    
    int numedge, head[maxn], n, m, x, sum, depth[maxn];
    inline void _ADD(int from, int to, int val) {
        e[numedge].to = to;
        e[numedge].val = val;
        e[numedge].nxt = head[from];
        head[from] = numedge;
        numedge++;
    }
    
    inline void AddEdge(int from, int to, int val) {
        _ADD(from, to, val);
        _ADD(to, from, 0);
    }
    
    inline bool bfs() {
        memset(depth, 0, sizeof(depth));
        depth[S] = 1;
        queue<int> q;
        q.push(S);
        while (!q.empty()) {
            int u = q.front();
            q.pop();
            for (int i = head[u]; ~i; i = e[i].nxt) {
                int to = e[i].to;
                if (!depth[to] && e[i].val > 0) {
                    depth[to] = depth[u] + 1;
                    q.push(to);
                }
            }
        }
        return depth[T];
    }
    
    int dfs(int u, int flow) {
        if (u == T || !flow) return flow;
        int res = 0;
        for (int i = head[u]; ~i; i = e[i].nxt) {
            int to = e[i].to;
            if (depth[to] > depth[u] && e[i].val) {
                int di = dfs(to, min(flow, e[i].val));
                if (di) {
                    flow -= di;
                    e[i].val -= di;
                    e[i ^ 1].val += di;
                    res += di;
                }
            }
        }
        if (!res) depth[u] = 0;
        return res;
    }
    
    inline int Dinic() {
        int res = 0;
        while (bfs())
            res += dfs(S, INF);
        return res;
    }
    
    int main() {
        memset(head, -1, sizeof(head));
        scanf("%d%d", &n, &m);
        for (int i = 1; i <= n; i++) {
            for (int j = 1; j <= m; j++) {
                scanf("%d", &x);
                sum += x;
                if (!((i + j) & 1)) {
                    AddEdge(S, (i - 1) * m + j, x);
                    for (int k = -1; k <= 1; k += 2) {
                        if (i + k > 0 && i + k <= n) AddEdge((i - 1) * m + j, (i + k - 1) * m + j, INF);
                        if (j + k > 0 && j + k <= m) AddEdge((i - 1) * m + j, (i - 1) * m + j + k, INF);
                    }
                }
                else {
                    AddEdge((i - 1) * m + j, T, x);
                }
            }
        }
        printf("%d
    ", sum - Dinic());
        return 0;
    }
    
  • 相关阅读:
    继承
    类和对象
    Scanner类
    面向对象思想
    final关键字
    The difference between text mode and binary mode with file streams
    Linux下常见权限操作相关命令
    Failed to start component [StandardEngine[Catalina].StandardHost[localhost].StandardContext
    手动运行jar包,指定配置文件
    jdk 1.8.0_131 Class JavaLaunchHelper is implemented
  • 原文地址:https://www.cnblogs.com/icysky/p/13623285.html
Copyright © 2020-2023  润新知