bzoj2127: happiness(最小割)

传送门
按题意建个图跑最大流-最小割算法
以上纯属扯淡。
按如下方式建图(借用黄学长的blog):

s->A:cost[A文]+c[文][A][B]/2,s->B:cost[B文]+c[文][A][B]/2;

A->t:cost[A理]+c[理][A][B]/2,B->t:costB[理]+c[理][A][B]/2;

A<–>B:c[文][A][B]/2+c[理][A][B]/2

代码:

#include<bits/stdc++.h>
#define ri register int
using namespace std;
const int rlen=1<<18|1,inf=0x3f3f3f3f;
inline char gc(){
    static char buf[rlen],*ib,*ob;
    (ib==ob)&&(ob=(ib=buf)+fread(buf,1,rlen,stdin));
    return ib==ob?-1:*ib++;
}
inline int read(){
    int ans=0;
    char ch=gc();
    while(!isdigit(ch))ch=gc();
    while(isdigit(ch))ans=((ans<<2)+ans<<1)+(ch^48),ch=gc();
    return ans;
}
const int M=10005,N=105;
int n,m,a[N][N],b[N][N],id[N][N],da[N][N],db[N][N],dc[N][N],dd[N][N];
struct edge{int v,next,c;};
namespace Dinic{
    int d[M],first[M],cnt,s,t;
    edge e[M*105];
    inline void addedge(int u,int v,int c){e[++cnt]=(edge){v,first[u],c},first[u]=cnt;}
    inline void add(int u,int v,int c){addedge(u,v,c),addedge(v,u,0);}
    inline void Add(int u,int v,int c){addedge(u,v,c),addedge(v,u,c);}
    inline void clear(){cnt=-1,memset(first,-1,sizeof(first)),s=0,t=n*m+1;}
    inline bool bfs(){
        queue<int>q;
        for(ri i=s;i<=t;++i)d[i]=-1;
        q.push(s),d[s]=0;
        while(q.size()){
            int x=q.front();
            q.pop();
            for(ri v,i=first[x];~i;i=e[i].next){
                if(~d[v=e[i].v]||!e[i].c)continue;
                d[v]=d[x]+1;
                q.push(v);
            }
        }
        return ~d[t];
    }
    inline int dfs(int x,int f){
        if(!f||x==t)return f;
        int flow=f;
        for(ri i=first[x],tmp,v;~i;i=e[i].next){
            if(!flow)return f;
            if(d[v=e[i].v]!=d[x]+1||!e[i].c)continue;
            tmp=dfs(v,min(flow,e[i].c));
            if(!tmp)d[v]=-1;
            e[i].c-=tmp,e[i^1].c+=tmp,flow-=tmp;
        }
        return f-flow;
    }
    inline int solve(){
        int ret=0;
        while(bfs())ret+=dfs(s,inf);
        return ret;
    }
}
int main(){
    int ans=0;
    n=read(),m=read();
    Dinic::clear();
    for(ri i=1,tim=0;i<=n;++i)for(ri j=1;j<=m;++j)id[i][j]=++tim;
    for(ri i=1;i<=n;++i)for(ri j=1;j<=m;++j)ans+=(a[i][j]=read()),a[i][j]<<=1;
    for(ri i=1;i<=n;++i)for(ri j=1;j<=m;++j)ans+=(b[i][j]=read()),b[i][j]<<=1;
    for(ri i=1,v;i<n;++i)for(ri j=1;j<=m;++j)ans+=(v=read()),a[i][j]+=v,a[i+1][j]+=v,da[i][j]=v;
    for(ri i=1,v;i<n;++i)for(ri j=1;j<=m;++j)ans+=(v=read()),b[i][j]+=v,b[i+1][j]+=v,db[i][j]=v;
    for(ri i=1,v;i<=n;++i)for(ri j=1;j<m;++j)ans+=(v=read()),a[i][j]+=v,a[i][j+1]+=v,dc[i][j]=v;
    for(ri i=1,v;i<=n;++i)for(ri j=1;j<m;++j)ans+=(v=read()),b[i][j]+=v,b[i][j+1]+=v,dd[i][j]=v;
    for(ri i=1;i<=n;++i)for(ri j=1;j<=m;++j){
        Dinic::add(Dinic::s,id[i][j],a[i][j]);
        Dinic::add(id[i][j],Dinic::t,b[i][j]);
        if(i^n)Dinic::Add(id[i][j],id[i+1][j],da[i][j]+db[i][j]);
        if(j^m)Dinic::Add(id[i][j],id[i][j+1],dc[i][j]+dd[i][j]);
    }
    cout<<ans-Dinic::solve()/2;
    return 0;
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值