【24题】方格取数问题【网络流】

题目大意:

在一个有 n×mn\times m 个方格的棋盘中,每个方格中有一个正整数。现要从方格中取数,使任意 2 个数所在方格没有公共边,且取出的数的总和最大。


思路:

这道题明显是一个二分图。我们可以把每个点染色,将i+ji+j为偶数的点连向tt,否则连向ss。那么对于每一个连ss的白点,将它连向它周围的四个黑点,容量为INFINF。跑一边最大流即可。


代码:

#include <cstdio>
#include <iostream>
#include <queue>
#include <cstring>
#define Inf 0x7f
#define INF 1e9
using namespace std;

int n,m,s,t,x,y,k,head[200001],dep[200001],ans,sum,num;

struct edge
{
    int next,to,c;
}e[200001];

void add(int from,int to,int c)
{
    k++;
    e[k].to=to;
    e[k].c=c;
    e[k].next=head[from];
    head[from]=k;
}

bool bfs()
{
    memset(dep,Inf,sizeof(dep));
    dep[s]=0;
    queue<int> q;
    q.push(s);
    while (q.size())
    {
        int u=q.front();
        q.pop();
        for (int i=head[u];i;i=e[i].next)
        {
            int v=e[i].to;
            if (dep[v]>dep[u]+1&&e[i].c)
            {
                dep[v]=dep[u]+1;
                q.push(v);
            }
        }
    }
    return dep[t]<Inf;
}

int dfs(int u,int low)
{
    int lows=0;
    if (u==t) return low;
    for (int i=head[u];i;i=e[i].next)
    {
        int v=e[i].to;
        if (dep[v]==dep[u]+1&&e[i].c)
        {
            lows=dfs(v,min(e[i].c,low));
            if (lows)
            {
                e[i].c-=lows;
                e[i^1].c+=lows;
                return lows;
            }
        }
    }
    return 0;
}

  //以上为最大流模板

int main()
{
    scanf("%d%d",&n,&m);
    k=1;
    s=n*m+4;
    t=n*m+5;
    for (int i=1;i<=n;i++)
     for (int j=1;j<=m;j++)
     {
     	scanf("%d",&x);
     	num+=x;
     	y=i*m-m+j;
     	if (!((i+j)%2))  //黑点
     	{
     		add(y,t,x);
     		add(t,y,0);
     	}
     	else  //白点
     	{
     		add(s,y,x);
     		add(y,s,0);
     		if (i>1)  //连上面的黑点
     		{
     			add(y,y-m,INF);
     			add(y-m,y,0);
     		}
     		if (i<n)  //连下面的黑点
     		{
     			add(y,y+m,INF);
     			add(y+m,y,0);
     		}
     		if (j>1)  //连左边的黑点
     		{
     			add(y,y-1,INF);
     			add(y-1,y,0);
     		}
     		if (j<m)  //连右边的黑点
     		{
     			add(y,y+1,INF);
     			add(y+1,y,0);
     		}
     	}
     }
     
    while (bfs())
    {
        while (sum=dfs(s,INF+1))
         ans+=sum;
    }
    printf("%d\n",num-ans);
    return 0;
}
posted @ 2018-08-11 09:31  全OI最菜  阅读(87)  评论(0编辑  收藏  举报