【BZOJ2502】清理雪道

Zarxdy34 posted @ 2015年12月15日 18:47 in BZOJ with tags 网络流 最小流 , 208 阅读

    一道最小流的题。设虚拟源汇为s,t(就是把图从无源无汇变成有源有汇的),超级源汇(用于求上下界)ss,st。

    建图:先按常规求上下界网络流的方法建图,连t->s,第一遍求出ss到st的最大流,则t->s边上的流为当前的可行流流量;然后删除与ss,st相连的所有边,删除t->s这条边,连ss->t,s->st,再求一遍ss到st的最大流把第一次可行流的跑多出来的流量跑回去。答案即第一次跑出来t->s边上流量减去第二次跑出来的最大流。

 

 

#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int maxn=110,maxm=maxn*maxn,inf=~0U>>2;
 
int head[maxn],next[maxm<<1],E[maxm<<1],F[maxm<<1],cur[maxn],Ecnt;
int n,ss,st,s,t,ans;
 
void Add_Edge(int x,int y,int flow) {next[++Ecnt]=head[x];head[x]=Ecnt;E[Ecnt]=y;F[Ecnt]=0;next[++Ecnt]=head[y];head[y]=Ecnt;E[Ecnt]=x;F[Ecnt]=flow;}
 
int InFlow[maxn];
 
void Init()
{
    scanf("%d",&n);
    s=n+1;t=n+2;ss=n+3;st=n+4;Ecnt=1;
    for (int i=1;i<=n;i++)
    {
        int mi,v;scanf("%d",&mi);
        while (mi--) scanf("%d",&v),Add_Edge(i,v,inf),InFlow[i]--,InFlow[v]++;
        Add_Edge(s,i,inf);
        Add_Edge(i,t,inf);
    }
    for (int i=1;i<=n;i++) if (InFlow[i]>0) Add_Edge(ss,i,InFlow[i]);else if (InFlow[i]<0) Add_Edge(i,st,-InFlow[i]);
    Add_Edge(t,s,inf);
}
 
int q[maxn],h[maxn],qhead,qtail;
bool BFS(int S,int T)
{
    memset(h,0,sizeof(h));
    for (int i=1;i<=n+4;i++) cur[i]=head[i];
    q[qhead=qtail=1]=S;
    h[S]=1;
    while (qhead<=qtail)
    {
        int x=q[qhead++];
        for (int i=head[x];i;i=next[i]) if (!h[E[i]] && F[i^1]) q[++qtail]=E[i],h[E[i]]=h[x]+1;
    }
    return h[T];
}
 
int DFS(int x,int T,int flow)
{
    if (x==T) return flow;
    int rest=flow;
    for (int &i=cur[x];i && rest;i=next[i]) if (h[E[i]]==h[x]+1 && F[i^1])
    {
        int d=DFS(E[i],T,min(F[i^1],rest));
        rest-=d;F[i]+=d;F[i^1]-=d;
    }
    if (flow==rest) h[x]=-1;
    return flow-rest;
}
 
int Dinic(int S,int T)
{
    int res=0;
    while (BFS(S,T)) res+=DFS(S,T,inf);
    return res;
}
 
void ReBuild()
{
    for (int i=1;i<=n+2;i++)
    {
        if (E[head[i]]==ss || E[head[i]]==st) head[i]=next[head[i]];
        else for (int j=head[i];j;j=next[j])
            if (E[next[j]]==ss || E[next[j]]==st) next[j]=next[next[j]];
    }
    for (int i=head[t];i;i=next[i]) if (E[i]==s) ans=F[i],F[i]=F[i^1]=0;
    Add_Edge(ss,t,inf);
    Add_Edge(s,st,inf);
}
 
int main()
{
    Init();
    Dinic(ss,st);
    ReBuild();
    ans-=Dinic(ss,st);
    printf("%d\n",ans);
    return 0;
}
Avatar_small
Zarxdy34 说:
2016年3月17日 07:59

你TM还能写得再简单一点吗...


登录 *


loading captcha image...
(输入验证码)
or Ctrl+Enter

Copyright © 2007

Webdesign, tvorba www stránek

Valid XHTML 1.1