P2774 方格取数问题(最小割)

P2774 方格取数问题

一看题目便知是网络流,但由于无法建图....

题目直说禁止那些条件,这导致我们直接建图做不到,既然如此,我们这是就要逆向思维,他禁止那些边,我们就连那些边.

我们将棋盘染色,一个点向四周连边,我们的目标是使的这些边不起作用,我们将黑点与s联通,白点与t联通.

之后我们就要考虑一个事情,只要一个黑点与白点由流,此时一定s到t有流.这样我们就能想到最小割...

#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int N=110,INF=2e9;
int sum,n,m,tot=1,s,t,dx[4]={-1,1,0,0},dy[4]={0,0,-1,1},d[N*N],current[N*N];
int link[N*N],c[N][N];
struct edge{int y,v,next;}a[N*N*8];
inline int read()
{
    int x=0,ff=1;
    char ch=getchar();
    while(!isdigit(ch)) {if(ch==‘-‘) ff=-1;ch=getchar();}
    while(isdigit(ch)) {x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
    return x*ff;
}
inline void add(int x,int y,int v)
{
    a[++tot].y=y;a[tot].v=v;a[tot].next=link[x];link[x]=tot;
    a[++tot].y=x;a[tot].v=0;a[tot].next=link[y];link[y]=tot;
}
inline bool bfs()
{
    queue<int>q;q.push(s);
    memset(d,0,sizeof(d));
    memcpy(current,link,sizeof(current));
    d[s]=1;
    while(!q.empty())
    {
        int x=q.front();q.pop();
        for(int i=link[x];i;i=a[i].next)
        {
            int y=a[i].y;
            if(d[y]||!a[i].v) continue;
            d[y]=d[x]+1;
            q.push(y);
            if(y==t) return true;
        }
    }
    return false;
}
inline int dinic(int x,int flow)
{
    if(x==t) return flow;
    int rest=flow,k;
    for(int i=current[x];i&&rest;i=a[i].next)
    {
        current[x]=i;
        int y=a[i].y;
        if(d[y]==d[x]+1&&a[i].v)
        {
            k=dinic(y,min(rest,a[i].v));
            if(!k) d[y]=0;
            a[i].v-=k;
            a[i^1].v+=k;
            rest-=k;
        }
    }
    return flow-rest;
}
int main()
{
    freopen("1.in","r",stdin);
    n=read();m=read();
    for(int i=1;i<=n;++i)
        for(int j=1;j<=m;++j) c[i][j]=read(),sum+=c[i][j];
    s=0;t=n*m+1;
    for(int i=1;i<=n;++i)
        for(int j=1;j<=m;++j)
        {
            if((i+j)%2==0)
            {
                add(s,(i-1)*m+j,c[i][j]);
                for(int k=0;k<4;++k)
                {
                    int x=i+dx[k],y=j+dy[k];
                    if(x>=1&&x<=n&&y>=1&&y<=m) add((i-1)*m+j,(x-1)*m+y,INF);
                }
            }
            else add((i-1)*m+j,t,c[i][j]);
        }
    int maxflow=0,flow;
    while(bfs())
        while(flow=dinic(s,INF)) maxflow+=flow;
    printf("%d",sum-maxflow);
    return 0;
}

原文地址:https://www.cnblogs.com/gcfer/p/12544244.html

时间: 2024-08-21 16:20:48

P2774 方格取数问题(最小割)的相关文章

LuoguP2774 方格取数问题(最小割)

题目背景 none! 题目描述 在一个有 m*n 个方格的棋盘中,每个方格中有一个正整数.现要从方格中取数,使任意 2 个数所在方格没有公共边,且取出的数的总和最大.试设计一个满足要求的取数算法.对于给定的方格棋盘,按照取数要求编程找出总和最大的数. 输入输出格式 输入格式: 第 1 行有 2 个正整数 m 和 n,分别表示棋盘的行数和列数.接下来的 m 行,每行有 n 个正整数,表示棋盘方格中的数. 输出格式: 程序运行结束时,将取数的最大总和输出 解题思路: 想个办法将选一个点和不选周围点关

【luogu 2774】方格取数 (最小割)

题目链接 [题目大意] 有n*m的方格,在其中取任意个格子的数,保证最终结果最大,取得数字不能相邻 [题目思路] 如果不是知道是网络流的题,大概会试下爆搜,取之后周围的不可取之类的,但是显而易见会T 然后考虑怎么用网络流做,为什么能用网络流做 我自己对于网络流的理解,是解决选择之间的直接冲突,从而得到最优解的方法,而这个题每一个数字选和不选之间就会发生冲突 [建图] 如何实现选择 拆点,这里大多数程序都是将点根据(i+j)分成两类,我觉得是为了代码更简洁些,如果把所有点都拆成两个的话还是可行的

方格取数问题 最小割

题目背景 none! 题目描述 在一个有 m*n 个方格的棋盘中,每个方格中有一个正整数.现要从方格中取数,使任意 2 个数所在方格没有公共边,且取出的数的总和最大.试设计一个满足要求的取数算法.对于给定的方格棋盘,按照取数要求编程找出总和最大的数. 输入输出格式 输入格式: 第 1 行有 2 个正整数 m 和 n,分别表示棋盘的行数和列数.接下来的 m 行,每行有 n 个正整数,表示棋盘方格中的数. 输出格式: 程序运行结束时,将取数的最大总和输出 输入输出样例 输入样例#1: 复制 3 3

HDU 1569 方格取数(2) (最小割)

题意:中文题. 析:很明显的是二分图的最大独立集,但是每个点都有权值,这个可以用最小割来求,建立一个超级源点s,和汇点t,然后s 向 X集,添加容量为权值的边,Y集向 t 添加容量为权值的,然后跑一遍最小割,然后用总权值减去就是答案了. 代码如下: #pragma comment(linker, "/STACK:1024000000,1024000000") #include <cstdio> #include <string> #include <cst

P2774 方格取数问题 网络最大流 割

P2774 方格取数问题:https://www.luogu.org/problemnew/show/P2774 题意: 给定一个矩阵,取出不相邻的数字,使得数字的和最大. 思路: 可以把方格分成两个部分,横坐标和纵坐标和为奇数的一组,和为偶数的一组,超级源点向偶数一组连容量为格点数字大小的边,奇数一组向超级汇点连容量为格点大小的边.然后两组间相临的点连容量为无穷的边. 跑出这个图的最大流,相当于是最小割,就是去掉了最少的部分使得网络不流通.因此答案就是sum - dinic(): #inclu

P2774 方格取数问题 网络流

题目: P2774 方格取数问题 题目背景 none! 题目描述 在一个有 m*n 个方格的棋盘中,每个方格中有一个正整数.现要从方格中取数,使任意 2 个数所在方格没有公共边,且取出的数的总和最大.试设计一个满足要求的取数算法.对于给定的方格棋盘,按照取数要求编程找出总和最大的数. 输入输出格式 输入格式: 第 1 行有 2 个正整数 m 和 n,分别表示棋盘的行数和列数.接下来的 m 行,每行有 n 个正整数,表示棋盘方格中的数. 输出格式: 程序运行结束时,将取数的最大总和输出 输入输出样

P2774 方格取数问题 网络流重温

P2774 方格取数问题 这个题目之前写过一次,现在重温还是感觉有点难,可能之前没有理解透彻. 这个题目要求取一定数量的数,并且这些数在方格里面不能相邻,问取完数之后和最大是多少. 这个很好的用了网络流的最大独立集. 根据位置把这些数分成了两个独立集,两个独立集的意思是这两个集合之间有关系,但是集合内部没有任何关系, 所以是两个独立集. 分成独立集之后,我们就要建图连边,这些都很好做,但是为什么答案就是  所有数之和-最小割 因为当我们跑一次最小割之和是不是让这个图没有连接了,也就是这个图不是联

[洛谷P2774] 方格取数问题

题意 在一个有 m*n 个方格的棋盘中,每个方格中有一个正整数.现要从方格中取数,使任意 2 个数所在方格没有公共边,且取出的数的总和最大. 想法 我们将问题转化为:一开始所有格子都选,之后去掉价值和最少的一些格子使剩下的格子合法. 将方格黑白染色,白格子连向S,黑格子连向T,边权为这个格子的值(也就是说将格子转移到边上). 相邻的黑白格子间连INF的边.(这样每条从S到T的路径都为 S->白格子->黑格子->T , 这两个格子不能同时选,S->白格子 与 黑格子->T 间必

P2774 方格取数问题

\(\color{#0066ff}{题目描述}\) 在一个有 m*n 个方格的棋盘中,每个方格中有一个正整数.现要从方格中取数,使任意 2 个数所在方格没有公共边,且取出的数的总和最大.试设计一个满足要求的取数算法.对于给定的方格棋盘,按照取数要求编程找出总和最大的数. \(\color{#0066ff}{输入格式}\) 第 1 行有 2 个正整数 m 和 n,分别表示棋盘的行数和列数.接下来的 m 行,每行有 n 个正整数,表示棋盘方格中的数. \(\color{#0066ff}{输出格式}\