[Luogu P2774] [BZOJ 1475] 方格取数问题

版权声明:欢迎转载蒟蒻博客,但请注明出处:blog.csdn.net/lpa20020220 https://blog.csdn.net/LPA20020220/article/details/82349155

洛谷传送门

BZOJ传送门

题目描述

在一个有 m n 个方格的棋盘中,每个方格中有一个正整数。现要从方格中取数,使任意 2 个数所在方格没有公共边,且取出的数的总和最大。试设计一个满足要求的取数算法。对于给定的方格棋盘,按照取数要求编程找出总和最大的数。

输入输出格式

输入格式:

1 行有 2 个正整数 m n ,分别表示棋盘的行数和列数。接下来的 m 行,每行有 n 个正整数,表示棋盘方格中的数。

输出格式:

程序运行结束时,将取数的最大总和输出

输入输出样例

输入样例#1:

3 3
1 2 3
3 2 3
2 3 1 

输出样例#1:

11

说明

m , n 100

解题分析

网络流经典模型: 棋盘式。

考虑到一个格子只与其周围的四个格子冲突, 那么我们可以把所有格子染成黑白两色棋盘式, 从源点向黑点连流量为格子收益的边,白点向汇点连格子收益的边, 然后冲突的黑点向白点连边。 这样求出的最小割就是需要舍弃掉的最小值, 我们用总收益去减就好了。

代码如下:

#include <cstdio>
#include <cstring>
#include <cctype>
#include <algorithm>
#include <cstdlib>
#include <cmath>
#include <queue>
#define R register
#define IN inline
#define W while
#define MX 10050
#define gc getchar()
#define S 0
#define T 10001
#define INF 100000000
#define ll long long
template <class TT>
IN void in(TT &x)
{
    x = 0; R char c = gc;
    for (; !isdigit(c); c = gc);
    for (;  isdigit(c); c = gc)
    x = (x << 1) + (x << 3) + c - 48;
}
int m, n, cnt;
int head[MX], layer[MX];
struct Edge {int to, fl, nex;} edge[MX << 4];
IN int getid(R int x, R int y) {return (x - 1) * n + y;}
IN void add(R int from, R int to, R int fl)
{
    edge[++cnt] = {to, fl, head[from]}, head[from] = cnt;
    edge[++cnt] = {from, 0, head[to]}, head[to] = cnt;
}
int mp[105][105];
std::queue <int> q;
IN bool BFS()
{
    std::memset(layer, 0, sizeof(layer));
    layer[S] = 1; q.push(S); R int now, i;
    W (!q.empty())
    {
        now = q.front(); q.pop();
        for (i = head[now]; ~i; i = edge[i].nex)
        {
            if(edge[i].fl > 0 && !layer[edge[i].to])
            layer[edge[i].to] = layer[now] + 1, q.push(edge[i].to);
        }
    }
    return layer[T];
}
int DFS(R int now, R int val)
{
    if(now == T) return val;
    R int lef = val, buf;
    for (R int i = head[now]; ~i; i = edge[i].nex)
    {
        if(edge[i].fl > 0 && layer[edge[i].to] == layer[now] + 1)
        {
            buf = DFS(edge[i].to, std::min(lef, edge[i].fl));
            if(!buf) continue;
            edge[i].fl -= buf, lef -= buf, edge[i ^ 1].fl += buf;
            if(lef <= 0) return val;
        }
    }
    return val - lef;
}
IN ll init()
{
    ll ret = 0;
    W (BFS()) ret += DFS(S, INF);
    return ret;
}
int main(void)
{
    int s, id; in(m); n = m; ll sum = 0;
    std::memset(head, cnt = -1, sizeof(head));
    for (R int i = 1; i <= m; ++i)
    for (R int j = 1; j <= n; ++j)
    in(mp[i][j]), sum += mp[i][j];
    for (R int i = 1; i <= m; ++i)
    {
        s = (i & 1) ? 1 : 2;
        for (; s <= n; s += 2)
        {
            id = getid(i, s);
            add(S, id, mp[i][s]);
            if(s > 1) add(id, getid(i, s - 1), INF);
            if(s < n) add(id, getid(i, s + 1), INF);
            if(i > 1) add(id, getid(i - 1, s), INF);
            if(i < m) add(id, getid(i + 1, s), INF);
        }
    }
    for (R int i = 1; i <= m; ++i)
    {
        s = (i & 1) ? 2 : 1;
        for (; s <= n; s += 2) add(getid(i, s), T, mp[i][s]);
    }
    printf("%lld", sum - init());
}

猜你喜欢

转载自blog.csdn.net/LPA20020220/article/details/82349155
今日推荐