Luogu2774 方格取数问题

原题链接:https://www.luogu.org/problemnew/show/P2774

方格取数问题

题目描述

在一个有 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

题解

学习一波棋盘黑白染色跑网络流的技巧。

将网格染成棋盘一样黑白相间的样子,黑点一坨,白点一坨跑二分图。强制黑点向四周的白点连边,边权 i n f ;超级源点向黑点连边,边权为点权;白点向超级汇点连边,边权为点权。

乖乖跑最小割。。。

代码
#include<bits/stdc++.h>
#define inf 0x3f3f3f3f
using namespace std;
const int M=2e4+5;
struct sd{int to,fl;}ed[M];
int start,end,id,n,m,sum,lay[M],itr[M];
vector<int>mmp[M];
queue<int>dui;
void add(int f,int t,int v)
{
    if(f<=0||t<=0)return;
    mmp[f].push_back(id);ed[id++]=(sd){t,v};
    mmp[t].push_back(id);ed[id++]=(sd){f,0};
}
void in()
{
    int a,pos;
    scanf("%d%d",&n,&m);start=n*m+1;end=n*m+2;
    for(int i=1;i<=n;++i)for(int j=1;j<=m;++j)
    {
        scanf("%d",&a);pos=j+(i-1)*m;sum+=a;
        if((i+j)%2)
        {
            add(start,pos,a);
            if(j>1)add(pos,pos-1,inf);
            if(j<m)add(pos,pos+1,inf);
            if(i>1)add(pos,pos-m,inf);
            if(i<n)add(pos,pos+m,inf);
        }
        else add(pos,end,a);
    }
}
bool bfs(int s,int e)
{
    memset(lay,0,sizeof(lay));memset(itr,0,sizeof(itr));
    lay[s]=1;dui.push(s);
    int f,to,fl,hh;
    while(!dui.empty())
    {
        f=dui.front();dui.pop();
        for(int i=mmp[f].size()-1;i>=0;--i)
        {
            hh=mmp[f][i];to=ed[hh].to;fl=ed[hh].fl;
            if(lay[to]||!fl)continue;
            lay[to]=lay[f]+1;dui.push(to);
        }
    }
    return lay[e];
}
int dfs(int s,int e,int mn)
{
    if(s==e||!mn)return mn;
    int ans=0,tmp,hh,to,fl,siz=mmp[s].size()-1;
    for(int i=itr[s];i<=siz;++i)
    {
        hh=mmp[s][i];to=ed[hh].to;fl=ed[hh].fl;
        if(lay[s]+1!=lay[to]||!fl)continue;
        tmp=dfs(to,e,min(mn-ans,fl));
        if(!tmp)continue;
        ed[hh].fl-=tmp;ed[hh^1].fl+=tmp;
        ans+=tmp;itr[s]=i;
        if(mn==tmp)break;
    }
    return ans;
}
void ac()
{
    int ans=0;
    while(bfs(start,end))ans+=dfs(start,end,inf);
    printf("%d",sum-ans);
}
int main(){in();ac();} 

猜你喜欢

转载自blog.csdn.net/shadypi/article/details/80841243