zoj 3475 最小割 巧妙建图
第一次接触这种类型的建图题,记录一下
题意:在一个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; }