洛谷 P1935 [国家集训队]圈地计划 最小割

题目描述

最近房地产商GDOI(Group of Dumbbells Or Idiots)从NOI(Nuts Old Idiots)手中得到了一块开发土地。据了解,这块土地是一块矩形的区域,可以纵横划分为N×M块小区域。GDOI要求将这些区域分为商业区和工业区来开发。根据不同的地形环境,每块小区域建造商业区和工业区能取得不同的经济价值。更具体点,对于第i行第j列的区域,建造商业区将得到Aij收益,建造工业区将得到Bij收益。另外不同的区域连在一起可以得到额外的收益,即如果区域(i,j)相邻(相邻是指两个格子有公共边)有k块(显然k不超过4)类型不同于(i,j)的区域,则这块区域能增加k×Cij收益。经过Tiger.S教授的勘察,收益矩阵A,B,C都已经知道了。你能帮GDOI求出一个收益最大的方案么?

输入输出格式

输入格式:
输入第一行为两个整数,分别为正整数N和M,分别表示区域的行数和列数;

第2到N+1列,每行M个整数,表示商业区收益矩阵A;

第N+2到2N+1列,每行M个整数,表示工业区收益矩阵B;

第2N+2到3N+1行,每行M个整数,表示相邻额外收益矩阵C。

输出格式:
输出只有一行,包含一个整数,为最大收益值。

输入输出样例

输入样例#1:
3 3
1 2 3
4 5 6
7 8 9
9 8 7
6 5 4
3 2 1
1 1 1
1 3 1
1 1 1
输出样例#1:
81
说明

N, M ≤ 100; 0 ≤ Aij, Bij, Cij ≤ 1000

对于30%的数据有N, M ≤ 6

对于50%的数据有N, M ≤ 20

对于100%的数据有N, M ≤ 100

分析:
显然是一个最小割模型。
大概长这样……
这里写图片描述
然而这题是不同的有贡献,那就把左右对调即可,因为这个是棋盘,可以使用黑白染色。

代码:

#include <iostream>
#include <cmath>
#include <cstdio>
#include <queue>

const int maxn=1e5+7;
const int maxe=3e5+7;
const int inf=0x3f3f3f3f;

using namespace std;

struct edge{
    int y,w,op,next;
}g[maxn];

int n,m,s,t,cnt,x,ans;
int ls[maxn],dis[maxn],v[maxn];
int c[105][105];
int dx[4]={-1,0,1,0};
int dy[4]={0,1,0,-1};

queue <int> q;

int po(int x,int y)
{
    return (x-1)*m+y;
}

void add(int x,int y,int w)
{
    g[++cnt]=(edge){y,w,cnt+1,ls[x]};
    ls[x]=cnt;
    g[++cnt]=(edge){x,0,cnt-1,ls[y]};
    ls[y]=cnt;
}

bool bfs()
{
    while (!q.empty()) q.pop();
    for (int i=s;i<=t;i++) dis[i]=inf;
    dis[s]=0;
    q.push(s);
    while (!q.empty())
    {
        int x=q.front();
        q.pop();
        for (int i=ls[x];i>0;i=g[i].next)
        {
            int y=g[i].y;
            if ((g[i].w) && (dis[y]>dis[x]+1))
            {
                dis[y]=dis[x]+1;
                q.push(y);
            }
        }
    }
    if (dis[t]!=inf) return 1;
                else return 0;
}

int dfs(int x,int maxf)
{
    if ((x==t) || (maxf==0)) return maxf;
    int ret=0;
    for (int i=ls[x];i>0;i=g[i].next)
    {
        int y=g[i].y;
        if ((dis[y]==dis[x]+1) && (g[i].w))
        {
            int f=dfs(y,min(maxf-ret,g[i].w));
            ret+=f;
            g[i].w-=f;
            g[g[i].op].w+=f;
        }
    }
    return ret;
}

int main()
{
    scanf("%d%d",&n,&m);
    s=0; t=n*m+1; 
    for (int i=1;i<=n;i++)
    {
        for (int j=1;j<=m;j++)
        {
            scanf("%d",&x);
            ans+=x;
            if ((i+j)%2) add(s,po(i,j),x);
                    else add(po(i,j),t,x);
        }
    }
    for (int i=1;i<=n;i++)
    {
        for (int j=1;j<=m;j++)
        {
            scanf("%d",&x);
            ans+=x;
            if ((i+j)%2) add(po(i,j),t,x);
                    else add(s,po(i,j),x);
        }
    }
    for (int i=1;i<=n;i++)
    {
        for (int j=1;j<=m;j++)
        {
            scanf("%d",&c[i][j]);
        }
    }
    for(int i=1;i<=n;i++)
    {
        for (int j=1;j<=m;j++)
        {
            if ((i+j)%2) continue;
            for (int k=0;k<=3;k++)
            {
                int x=i+dx[k];
                int y=j+dy[k];
                if ((x>0) && (y>0) && (x<=n) && (y<=m))
                {
                    add(po(x,y),po(i,j),c[x][y]+c[i][j]);
                    add(po(i,j),po(x,y),c[x][y]+c[i][j]);
                    ans+=c[x][y]+c[i][j];
                }
            }
        }
    }
    while (bfs()) ans-=dfs(s,inf);
    printf("%d",ans);
}

猜你喜欢

转载自blog.csdn.net/liangzihao1/article/details/81637148
今日推荐