zoj 3475 最小割 巧妙建图

来源:互联网 发布:excel跨工作簿引用数据 编辑:程序博客网 时间:2024/05/17 23:02

第一次接触这种类型的建图题,记录一下

题意:在一个20*20的方格中,建造一些围墙,使得X和某些A与E和外界都不联通,建造围墙有对应的花费,而对于满足条件的A,有对应的收入。

首先2^5枚举哪些A要被围住,然后就要求所需的最小费用,这就是典型的最大流最小割问题。其中X和所枚举的A同源连一条流量为inf的边,E和边界同汇连一条流量为inf的边。

以上是watashi的简练题解,我等若菜一开始还没反应过来

为什么建好图后的最小割就是把X和一些A与E隔开的最小代价呢?注意,选择了某条边为割边就表示方格中两个格子间的那条围墙被选择了。

注意到S集合是X和A,T集合是E和边界,所以求一下最小割后s集合中的点无法到达T集合了,

因此也就完成了把X和一些A围起来且与E隔开的功能

 

View Code
#include<cstdio>#include<cstring>#include<set>#include<algorithm>using namespace std;const int MAX=405;const int INF=1000000000;struct{    int v,c,next;}edge[2000],EDGE[2000];int E,head[MAX],S,T;int gap[MAX],cur[MAX];int pre[MAX],dis[MAX];void add_edge(int s,int t,int c){    edge[E].v=t; edge[E].c=c;    edge[E].next=head[s];    head[s]=E++;    edge[E].v=s; edge[E].c=c;    edge[E].next=head[t];    head[t]=E++;}int min(int a,int b){return (a==-1||b<a)?b:a;}int SAP(int s,int t,int n){    memset(gap,0,sizeof(gap));    memset(dis,0,sizeof(dis));    int i;    for(i=0;i<n;i++)cur[i]=head[i];    int u=pre[s]=s,maxflow=0,aug=-1,v;    gap[0]=n;        while(dis[s]<n){loop:    for(i=cur[u];i!=-1;i=edge[i].next){            v=edge[i].v;            if(edge[i].c>0&&dis[u]==dis[v]+1){                aug=min(aug,edge[i].c);                pre[v]=u;                cur[u]=i;                u=v;                if(u==t){                    for(u=pre[u];v!=s;v=u,u=pre[u]){                        edge[cur[u]].c-=aug;                        edge[cur[u]^1].c+=aug;                    }                    maxflow+=aug;                    aug=-1;                }                goto loop;            }        }        int mindis=n;        for(i=head[u];i!=-1;i=edge[i].next){            v=edge[i].v;            if(edge[i].c>0&&dis[v]<mindis){                cur[u]=i;                mindis=dis[v];            }        }        if((--gap[dis[u]])==0)break;        gap[dis[u]=mindis+1]++;        u=pre[u];    }    return maxflow;}int x[MAX],y[MAX],z[MAX],H[MAX],n,m;int ID(int x,int y){return x*m+y;}int main(){    while(scanf("%d%d",&n,&m)!=EOF){         S=n*m;T=n*m+1;         memset(head,-1,sizeof(head));         E=0;         for(int i=0,f;i<=n;i++){             for(int j=0;j<m;j++){                 scanf("%d",&f);                 add_edge(i==0 ? T : ID(i-1,j),i==n ? T : ID(i,j),f);             }             if(i==n) break;             for(int j=0,f;j<=m;j++){                 scanf("%d",&f);                 add_edge(j==0 ? T : ID(i,j-1) , j==m ? T : ID(i,j),f);             }         }         int k;         scanf("%d",&k);int t=k;         for(int i=0;i<t;i++){             scanf("%d%d%d",&z[i],&x[i],&y[i]);             if(z[i]==0){                 swap(z[i],z[0]);                 swap(y[i],y[0]);                 swap(x[i],x[0]);             }             else if(z[i]<0){                 add_edge(ID(x[i],y[i]),T,INF);                 i--;t--;             }         }         memcpy(EDGE,edge,sizeof(edge));         memcpy(H,head,sizeof(head));         int ans=INF;         int tmp=E;         for(int i=1,f=0;i<(1<<t);i+=2){             f=0;             memcpy(head,H,sizeof(H));             memcpy(edge,EDGE,sizeof(EDGE));E=tmp;             for(int j=0;j<t;j++){                 if(i&(1<<j)){                     add_edge(S,ID(x[j],y[j]),INF);                     f-=z[j];                 }                             }             f+=SAP(S,T,n*m+2);             ans=min(ans,f);         }         printf("%d\n",ans);    }    return 0;}