平面图最小割,注意双向边。

#include<cstdio>
#include<cstring>
#define rep(i,a,b) for(int i=(a);i<=(b);i++)
int S,T;
struct edge{
    int to,cap,rev,nx;  
}G[6000001];  
int n,m,x,p;
int lv[2000001],iter[2000001],h[2000001],q[7000001];
int P(int x,int y){return (x-1)*m+y;}
int read(){
    int x=0,f=1;char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
    return x*f;
}
int Min(int a,int b){return a<b?a:b;}  
void ae(int s,int e,int w){  
    G[++p]=(edge){e,w,p+1,h[s]};h[s]=p;
}
void bfs(int s){
    int he=0,ta=0;
    q[ta++]=s;lv[s]=1;
    while(he<ta){
        int x=q[he++];
        for(int i=h[x];i;i=G[i].nx){
            int v=G[i].to;
            if(!lv[v]&&G[i].cap) lv[v]=lv[x]+1,q[ta++]=v;
        }
    }
}
int dfs(int s,int f){
    int sum=0;
    if(s==T) return f;
    for(int &i=iter[s];i;i=G[i].nx){
        int v=G[i].to;
        if(lv[s]+1==lv[v]&&G[i].cap){
            int d=dfs(v,Min(G[i].cap,f));
            if(d) sum+=d,f-=d,G[i].cap-=d,G[G[i].rev].cap+=d;
            if(f==0) return sum;
        }
    }
    return sum;
}
int dinic(int s,int t){
    int fl=0;
    while(1){
        for(int i=S;i<=T;i++)iter[i]=h[i];
        memset(lv,0,sizeof(lv));
        bfs(s);if(lv[t]==0) return fl;
        int d=dfs(s,2147483647);while(d>0){fl+=d;d=dfs(s,2147483647);}
    }
}
int main(){
    n=read();m=read();
    S=1,T=P(n,m);
    rep(i,1,n)rep(j,1,m-1){x=read();ae(P(i,j),P(i,j+1),x);ae(P(i,j+1),P(i,j),x);}
    rep(i,1,n-1)rep(j,1,m){x=read();ae(P(i,j),P(i+1,j),x);ae(P(i+1,j),P(i,j),x);}
    rep(i,1,n-1)rep(j,1,m-1){x=read();ae(P(i,j),P(i+1,j+1),x);ae(P(i+1,j+1),P(i,j),x);}
    printf("%d\n",dinic(S,T));
    return 0;
}

 

posted on 2017-08-17 10:50  nzher  阅读(119)  评论(0编辑  收藏  举报