列表

详情


NC213822. [网络流24题]方格取数问题

描述

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

输入描述

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

输出描述

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

示例1

输入:

3 3
1 2 3
3 2 3
2 3 1

输出:

11

原站题解

上次编辑到这里,代码来自缓存 点击恢复默认模板

C++ 解法, 执行用时: 5ms, 内存消耗: 528K, 提交时间: 2022-01-30 13:32:17

#include<iostream>
#include<cstring>
#include<queue>
using namespace std;
const int N = 10100,M = 1e6+10,inf=0x3f3f3f;
int h[N],ne[M],e[M],f[M],idx;
void add(int a,int b,int c){
    ne[idx] = h[a],e[idx] = b,f[idx] = c,h[a] = idx++;
    ne[idx] = h[b],e[idx] = a,f[idx] = 0,h[b] = idx++;
}
int pre[N],a[N];
int EK(int s,int t){
    int flow = 0;
    while(1){
        memset(a,0,sizeof a);
        queue<int> q;
        q.push(s);
        a[s] = inf;
        while(!q.empty()){
            int u = q.front();q.pop();
            for(int i = h[u];~i;i=ne[i]){
                int y = e[i];
                if(f[i] > 0 && !a[y]){
                    a[y] = min(a[u],f[i]);
                    pre[y] = i;
                    q.push(y);
                }
            }
            if(a[t])break;
        }
        if(!a[t])break;
        for(int i = t;i!=s;i=e[pre[i]^1]){
            f[pre[i]] -= a[t];
            f[pre[i]^1] += a[t];
        }
        flow += a[t];
    }
    return flow;
}
int n,m;
int main(){
    int tp,s = 0,t=1,sum=0;
    cin >> n >> m;
    memset(h,-1,sizeof h);
    for(int i = 1;i<=n;i++){
        for(int j = 1;j<=m;j++){
            cin >> tp;
            sum+=tp;
            if((i+j)&1){
                add(s,i*m+j,tp);
                if(i - 1 >= 1)add(i*m+j,(i-1)*m+j,inf);
                if(i + 1 <= n)add(i*m+j,(i+1)*m+j,inf);
                if(j - 1 >= 1)add(i*m+j,i*m+j-1,inf);
                if(j + 1 <= m)add(i*m+j,i*m+j+1,inf);
            }else{
                add(i*m+j,t,tp);
            }
        }
    }
    cout << sum - EK(s,t) << endl;
    return 0;
}

上一题