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

题解

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

将网格染成棋盘一样黑白相间的样子,黑点一坨,白点一坨跑二分图。强制黑点向四周的白点连边,边权 inf 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();} 
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

ShadyPi

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值