Luogu_2774 方格取数问题

Luogu_2774 方格取数问题

二分图最小割

第一次做这种题,对于某些强烈暗示性的条件并没有理解到。

也就是每一立刻理解到是这个图是二分图。

为什么?
横纵坐标为奇数的只会和横纵坐标为偶数的相连。

最大和=全局和-最小代价

所以可以反向缩小最小代价。

考虑奇数点与源点相连,偶数点与汇点相连,流量都是这个点的权值。

然后奇数点像偶数点连边,权值无限大。

这样构图。最小割是一个简单割。

割的流量就是最小的代价。

要么奇数点被割去,要么相邻的四个偶数点被割去

#include <algorithm>
#include <iostream>
#include <cstring>
#include <cstdio>
#include <queue>

using std::queue;
using std::min;

const int maxn=301;
const int inf=0x7fffffff;
const int dx[]={0,0,1,-1};
const int dy[]={1,-1,0,0};

struct node
{
    int p;
    int nxt;
    int value;
    node(int a=0,int b=0,int c=0)
    {
        p=a;
        value=b;
        nxt=c;
    }
};

node line[maxn*maxn<<1];
int head[maxn*maxn],tail;
int cur[maxn*maxn];
int Dis[maxn*maxn];
int Map[maxn][maxn];
int S,T;

void add(int a,int b,int c,int d)
{
    line[++tail]=node(b,c,head[a]);
    head[a]=tail;
    line[++tail]=node(a,d,head[b]);
    head[b]=tail;
}

void init(int n,int m)
{
    S=n*m;T=n*m+1;
    tail=-1;
    memset(head,-1,sizeof(head));
}

int Bfs(int s,int t)
{
    queue<int>q;
    memset(Dis,0,sizeof(Dis));
    Dis[s]=1;q.push(s);
    while(!q.empty())
    {
        int pas=q.front();q.pop();
        for(int i=head[pas];i!=-1;i=line[i].nxt)
        {
            int v=line[i].p;
            if(Dis[v]||!line[i].value)  continue;
            Dis[v]=Dis[pas]+1;
            q.push(v);
        }
    }
    for(int i=0;i<=T;i++)   cur[i]=head[i];
    return Dis[t];
}

int Dfs(int now,int aim,int limte)
{
    if(now==aim||!limte)    return limte;
    int res=0,f;
    for(int &i=cur[now];i!=-1;i=line[i].nxt)
    {
        int v=line[i].p;
        if(Dis[v]==Dis[now]+1&&(f=Dfs(v,aim,min(limte,line[i].value))))
        {
            res+=f;
            limte-=f;
            line[i].value-=f;
            line[i^1].value+=f;
            if(!limte)  break;
        }
    }
    return res;
}

int Dinic(int s,int t)
{
    int res=0;
    while(Bfs(s,t))
        res+=Dfs(s,t,inf);
    return res;
}

int main()
{
    int n,m,tot=0;
    scanf("%d%d",&n,&m);
    init(n,m);
    for(int i=0;i<n;i++)
        for(int j=0;j<m;j++)
            scanf("%d",&Map[i][j]);
    for(int i=0;i<n;i++)
        for(int j=0;j<m;j++)
        {
            if(((i+j)&1)==1)
            {
                add(S,i*m+j,Map[i][j],0);
                for(int k=0;k<4;k++)
                    if(i+dx[k]>=0&&i+dx[k]<n&&j+dy[k]>=0&&j+dy[k]<m)
                        add(i*m+j,(i+dx[k])*m+(j+dy[k]),inf,0);
            }
            else
                add(i*m+j,T,Map[i][j],0);
            tot+=Map[i][j];
        }
    printf("%d",tot-Dinic(S,T));
    return 0;
}

原文地址:https://www.cnblogs.com/Lance1ot/p/10295246.html

时间: 2024-10-09 05:27:38

Luogu_2774 方格取数问题的相关文章

hdu 1565 方格取数(2)(网络流之最大点权独立集)

题目链接:hdu 1565 方格取数(2) 题意: 有一个n*m的方格,每个方格有一个数,现在让你选一些数.使得和最大. 选的数不能有相邻的. 题解: 我们知道对于普通二分图来说,最大独立点集 + 最小点覆盖集 = 总点数,类似的,对于有权的二分图来说,有: 最大点权独立集 + 最小点权覆盖集 = 总点权和, 这个题很明显是要求 最大点权独立集 ,现在 总点权 已知,我们只要求出来 最小点权覆盖集 就好了,我们可以这样建图, 1,对矩阵中的点进行黑白着色(相邻的点颜色不同),从源点向黑色的点连一

P1004 方格取数

P1004 方格取数 题目描述 设有N*N的方格图(N<=9),我们将其中的某些方格中填入正整数,而其他的方格中则放 人数字0.如下图所示(见样例): A 0 0 0 0 0 0 0 0 0 0 13 0 0 6 0 0 0 0 0 0 7 0 0 0 0 0 0 14 0 0 0 0 0 21 0 0 0 4 0 0 0 0 15 0 0 0 0 0 0 14 0 0 0 0 0 0 0 0 0 0 0 0 0 0 . B 某人从图的左上角的A点出发,可以向下行走,也可以向右走,直到到达右下角

hdoj 1569 方格取数(2) 【最小割】 【最大点权独立集】

方格取数(2) Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others) Total Submission(s): 5589    Accepted Submission(s): 1741 Problem Description 给你一个m*n的格子的棋盘,每个格子里面有一个非负数. 从中取出若干个数,使得任意的两个数所在的格子没有公共边,就是说所取数所在的2个格子不能相邻,并且取出的

1475: 方格取数

1475: 方格取数 Time Limit: 5 Sec  Memory Limit: 64 MBSubmit: 578  Solved: 309[Submit][Status][Discuss] Description 在一个n*n的方格里,每个格子里都有一个正整数.从中取出若干数,使得任意两个取出的数所在格子没有公共边,且取出的数的总和尽量大. Input 第一行一个数n:(n<=30) 接下来n行每行n个数描述一个方阵 Output 仅一个数,即最大和 Sample Input 2 1 2

hdu 1569 方格取数(2) 网络流 最大点权独立集

方格取数(2) Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others) Total Submission(s): 5146    Accepted Submission(s): 1610 Problem Description 给你一个m*n的格子的棋盘,每个格子里面有一个非负数. 从中取出若干个数,使得任意的两个数所在的格子没有公共边,就是说所取数所在的2个格子不能相邻,并且取出的

HDU 1565 方格取数(1) (状态压缩 DP)

方格取数(1) Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 5779    Accepted Submission(s): 2194 Problem Description 给你一个n*n的格子的棋盘,每个格子里面有一个非负数. 从中取出若干个数,使得任意的两个数所在的格子没有公共边,就是说所取的数所在的2个格子不能相邻,并且取出

HDU 1565 方格取数(1)(状压dp)

感觉这道题目的数据比较水啊,程序的时间复杂度为1711^2*20竟然也可以过掉....其他的就是状压了啊,注意需要滚动一下啊.... 方格取数(1) Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 5701    Accepted Submission(s): 2159 Problem Description 给你一个n*n的格子的棋

hdu 3657 最小割的活用 / 奇偶方格取数类经典题 /最小割

题意:方格取数,如果取了相邻的数,那么要付出一定代价.(代价为2*(X&Y))(开始用费用流,敲升级版3820,跪...) 建图:  对于相邻问题,经典方法:奇偶建立二分图.对于相邻两点连边2*(X&Y),源->X连边,Y->汇连边,权值w为点权. ans=总点权-最小割:如果割边是源->X,表示x不要选(是割边,必然价值在路径上最小),若割边是Y-汇点,同理:若割边是X->Y,则表示选Y点且选X点, 割为w( 2*(X&Y) ). 自己的确还没有理解其本质

hdu 4859 最大点权独立集的变形(方格取数的变形)

/*刚开始不会写,最大点权独立集神马都不知道,在潘神的指导下终于做出来,灰常感谢ps: 和方格取数差不多奇偶建图,对于D必割点权为0,对于.必然不割点权为inf.然后和方格取数差不多的建图 .--.||E权值为2,,.||E--D权值为0. 最大点权独立集=sum-最小点权覆盖. */ #include<stdio.h> #include<string.h> #include<queue> using namespace std; #define inf 0x3ffff