【最小割】【BZOJ 3774】最优选择

Description

小N手上有一个N*M的方格图,控制某一个点要付出Aij的代价,然后某个点如果被控制了,或者他周围的所有点(上下左右)都被控制了,那么他就算是被选择了的。一个点如果被选择了,那么可以得到Bij的回报,现在请你帮小N选一个最优的方案,使得回报-代价尽可能大。

Input

第一行两个正整数N,M表示方格图的长与宽。

接下来N行每行M个整数Aij表示控制的代价。

接下来N行每行M个整数Bij表示选择的回报。

Output

一个整数,表示最大的回报-代价(如果一个都不控制那么就是0)。

Sample Input

3 3

1 100 100

100 1 100

1 100 100

2 0 0

5 2 0

2 0 0
Sample Output

8
HINT

对于100%的数据,N,M<=50,Aij,Bij都是小于等于100的正整数。

第一眼看见这道题,约束条件既有串又有并,根本没法建边啊!!!
后来上网一看,棋盘红黑染色是什么鬼。。。
反正后来画了个图,大概明白了。
我们先把棋盘上的格子分为奇数格和偶数格(x+y的奇偶性)
然后这样建边(反正讲是讲不清楚)

红色的代表占领该点的代价,绿色代表控制该点的收益,黑色代表边权为INT_MAX。
其中第一个图代表一个点和它周围几个点的连边。

剩下的看代码:

#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<queue>
#include<stack>
using namespace std;

#define MAXN 50
#define MAXM 50
#define INF 0x3f3f3f3f
typedef long long int LL;

int getint(){
    int rn=0;char c=getchar();bool flag=0;
    while(c<'0'||'9'<c){if(c=='-')flag=1;c=getchar();}
    while('0'<=c&&c<='9'){rn=rn*10+c-'0';c=getchar();}
    return flag?-rn:rn;
}

namespace ISAP{
    const int MAXP = MAXN*MAXM*3;
    const int MAXE = MAXN*MAXM*10;

    struct node{
        int v,c;
        node *nxt,*bck;
    }*adj[MAXP+10],Edges[MAXE*2+100],*New;

    int S,T,P;
    int d[MAXP+10],vd[MAXP+10];

    void init(int s,int t,int p){
        S=s,T=t,P=p;
        New=Edges;
        memset(adj,0,sizeof(adj));
    }

    void addedges(int u,int v,int c){
        node *p=++New;
        p->v=v;
        p->c=c;
        p->nxt=adj[u];
        p->bck=New+1;
        adj[u]=p;

        p=++New;
        p->v=u;
        p->c=0;
        p->nxt=adj[v];
        p->bck=New-1;
        adj[v]=p;
    }

    int aug(int x,int augco){
        if(x==T)return augco;

        int Dmin=P-1,delta,augc=augco;
        for(node *p=adj[x];p!=NULL;p=p->nxt)
            if(p->c){
                if(d[x]==d[p->v]+1){
                    delta=min(augc,p->c);
                    delta=aug(p->v,delta);

                    augc-=delta;
                    p->c-=delta;
                    p->bck->c+=delta;

                    if(d[S]>=P)
                        return augco-augc;
                    if(!augc)
                        break;
                }

                Dmin=min(Dmin,d[p->v]);
            }

        if(augco==augc){
            if(!(--vd[d[x]]))
                d[S]=P;
            ++vd[d[x]=Dmin+1];
        }

        return augco-augc;
    }

    int isap(){
        memset(d,0,sizeof(d));
        memset(vd,0,sizeof(vd));
        vd[0]=P;

        int flow=0;
        while(d[S]<P)
            flow+=aug(S,INF);

        return flow;
    }
}

const int dx[4]={0,1,0,-1};
const int dy[4]={1,0,-1,0};

int M,N,Cnt;
int id[MAXM+10][MAXN+10][2];

void Mark(){
    Cnt=0;
    for(int i=1;i<=M;++i)
        for(int j=1;j<=N;++j)
            id[i][j][0]=++Cnt,id[i][j][1]=++Cnt;
}

int main(){
    M=getint(),N=getint();
    int ans=0;
    Mark();

    ISAP::init(Cnt+1,Cnt+2,Cnt+2);

    int val;
    for(int i=1;i<=M;++i)//占领代价
        for(int j=1;j<=N;++j){
            val=getint();

            if((i+j)&1)
                ISAP::addedges(ISAP::S,id[i][j][0],val);
            else
                ISAP::addedges(id[i][j][0],ISAP::T,val);
        }

    for(int i=1;i<=M;++i)//控制收益
        for(int j=1;j<=N;++j){
            val=getint();
            ans+=val+val;

            if((i+j)&1){
                ISAP::addedges(ISAP::S,id[i][j][1],val);
                ISAP::addedges(id[i][j][0],ISAP::T,val);
            }
            else{
                ISAP::addedges(ISAP::S,id[i][j][0],val);
                ISAP::addedges(id[i][j][1],ISAP::T,val);
            }
        }

    int nx,ny;
    for(int i=1;i<=M;++i)
        for(int j=1;j<=N;++j){
            if((i+j)&1){
                ISAP::addedges(id[i][j][1],id[i][j][0],INF);

                for(int k=0;k<4;++k){
                    nx=i+dx[k],ny=j+dy[k];
                    if(nx<1||ny<1||nx>M||ny>N)continue;

                    ISAP::addedges(id[i][j][1],id[nx][ny][0],INF);
                }
            }
            else{
                ISAP::addedges(id[i][j][0],id[i][j][1],INF);

                for(int k=0;k<4;++k){
                    nx=i+dx[k],ny=j+dy[k];
                    if(nx<1||ny<1||nx>M||ny>N)continue;

                    ISAP::addedges(id[nx][ny][0],id[i][j][1],INF);
                }
            }
        }

    printf("%d\n",ans-ISAP::isap());
}
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值