方格取数问题

题目链接:

点我

题目分析:

网络流
考虑先将棋盘黑白染色变成二分图,这样使得每个格子有公共边的其他格子和它自己都是异色的,然后把它向其他四个方向的点连一下边,边容量\(INF\)\(S\)连黑点,容量为权值,白点连\(T\),容量同理
于是问题转化为一个最小割问题

代码:

#include<bits/stdc++.h>
#define INF (1000000000 + 7)
#define N (100000 + 10)
using namespace std;
inline int read() {
    int cnt = 0, f= 1;char c = getchar();
    while (!isdigit(c)) {if (c == '-') f = -f; c = getchar();}
    while (isdigit(c)) {cnt = (cnt << 3) + (cnt << 1) + (c ^ 48); c = getchar();}
    return cnt * f;
}
const int fx[5] = {0, 1, 0, -1, 0};
const int fy[5] = {0, 0, -1, 0, 1};
int m, n, s, t, first[N << 2], nxt[N << 2], to[N << 2], flow[N], tot = 1, dep[N], cnt[N], ans;
void add(int x, int y, int z) {nxt[++tot] = first[x], first[x] = tot, to[tot] = y, flow[tot] = z;}
int Map[110][110];
queue <int> q;
void build () {
    for (register int i = 1; i <= m; ++i) 
        for (register int j = 1; j <= n; ++j) {
            if ((i + j) & 1) add(s, (i - 1) * n + j, Map[i][j]), add((i - 1) * n + j, s, 0);
            else add(t, (i - 1) * n + j, 0), add((i - 1) * n + j, t, Map[i][j]);
        }
    for (register int i = 1; i <= m; ++ i)
        for (register int j = 1; j <= n; ++j) {
            if ((i + j) & 1) {
                for (register int k = 1; k <= 4; ++k) {
                    int x = i + fx[k], y = j + fy[k];
                    if (x < 1 || y < 1 || x > m || y > n) continue;
                    add((i - 1) * n + j, (x - 1) * n + y, INF);
                    add((x - 1) * n + y, (i - 1) * n + j, 0);
                }
            }
        }
}
void bfs_(int t) {
    memset(dep, 0xff, sizeof dep);
    dep[t] = 0, cnt[0] = 1;
    q.push(t);
    while (!q.empty()) {
        int p = q.front(); q.pop();
        for (register int i = first[p]; i; i = nxt[i]) {
            int v = to[i];
            if (dep[v] == -1) {
                ++cnt[dep[v] = dep[p] + 1];
                q.push(v);
            }
        }
    }
}
int max_flow;
int dfs_(int p, int f) {
    if (p == t) {max_flow += f; return f;}
    int u = 0;
    for (register int i = first[p]; i; i = nxt[i]) {
        int v = to[i];
        if (flow[i] && dep[v] == dep[p] - 1) {
            int uu = dfs_(v, min(flow[i], f - u));
            if (uu) {
                flow[i] -= uu, flow[i ^ 1] += uu, u += uu;
            }
            if (u >= f) return u;
        }
    }
    if (!--cnt[dep[p]]) dep[s] = m * n + 3;
    ++cnt[++dep[p]];
    return u;
}
int main() {
    m = read(), n = read();
    s = m * n + 1, t = m * n + 2;
    for (register int i = 1; i <= m; ++i) 
        for (register int j = 1; j <= n; ++j) 
            Map[i][j] = read(), ans += Map[i][j];
    build();
    bfs_(t);
    while (dep[s] < m * n + 3) dfs_(s, INF);
    printf("%d", ans - max_flow);
    return 0;
}
weixin063传染病防控宣传微信小程序系统的设计与实现+springboot后端毕业源码案例设计 1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md或论文文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。 5、资源来自互联网采集,如有侵权,私聊博主删除。 6、可私信博主看论文后选择购买源代码。 1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md或论文文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。 5、资源来自互联网采集,如有侵权,私聊博主删除。 6、可私信博主看论文后选择购买源代码。 1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md或论文文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。 5、资源来自互联网采集,如有侵权,私聊博主删除。 6、可私信博主看论文后选择购买源代码。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值