bzoj3698

来源:互联网 发布:淘宝网女士夏季服装 编辑:程序博客网 时间:2024/06/05 11:17

这道题网上题解到处都是,在此就不赘述了。
看到这题时,我一开始的想法是对于每个点Ai,j(其中i!=n && j!=n),向其所在行和列连边。
但这样是有问题的,因为可能行和列所连的边流量不同,这显然是不对的。
感觉网络流题目查错一般适合静态差错,因为网络流模板一般不太会打错,bug大多出在见图上,单步跟踪很难发现。
下面就是比q234rty大爷慢到不知道哪里去的代码。
upd:刚才突然发现自己不理解自己的做法了。
事实上,对于有源有汇有上下界的最大流,我在此的做法是先加附加源汇,跑一遍有源有汇有上下界的可行流,再在残量网络上跑最大流。本来答案应该是新增的流量加原始边的流量下界之和,但注意到t->s有一条(0,inf)的边,第一遍跑完后会产生流量为原始边的流量下界之和的反向边,然后第二遍时会把这条边的流量自动加上,就不必手动累加了。

#include <cstdio>const int N=310,M=100010,inf=1<<30;struct graph{    struct edge{        int to,next,flow;        edge(int _to=0,int _next=0,int _flow=0):to(_to),next(_next),flow(_flow){}    }e[M<<1];    int h[N],d[N],q[N],t,w,xb,n,cur[N],T;    void addedge(int x,int y,int z){        e[++xb]=edge(y,h[x],z);        h[x]=xb;        e[++xb]=edge(x,h[y],0);        h[y]=xb;    }    inline int o(int x){        if(x&1)return x+1;            else return x-1;    }    bool bfs(int x,int y){        for(int i=1;i<=n;++i)d[i]=cur[i]=0;d[x]=1;t=0;w=1;q[1]=x;        while(t<w){            int u=q[++t];            for(int i=h[u];i;i=e[i].next)                if(e[i].flow && !d[e[i].to]){                    d[e[i].to] =d[u]+1;                    q[++w]=e[i].to;                    if(e[i].to==T)return 1;                }        }        return d[y];    }    inline int min(int x,int y){        return x<y?x:y;    }    int dfs(int x,int f){        if(x==T || !f)return f;int flow=0;         for(int&i=cur[x];i;i=e[i].next)if(e[i].flow && d[e[i].to]==d[x]+1){            int a=dfs(e[i].to,min(f,e[i].flow));            if(a){                e[i].flow-=a;e[o(i)].flow+=a;flow+=a;f-=a;                if(!f)break;            }        }        return flow;    }    int maxflow(int x,int y){        T=y;        int ans=0;        while(bfs(x,y)){            for(int i=1;i<=n;++i)cur[i]=h[i];            ans+=dfs(x,1<<30);        }        return ans;    }}g;int n,i,u[M],v[M],l[M],r[M],x,z,xb,j,k=1,out[M],s;double y;int main(){    scanf("%d",&n);    u[xb=1]=n<<1,v[1]=1,l[1]=0,r[xb]=inf;    for(i=1;i<=n;++i)        for(j=1;j<=n;++j){            scanf("%lf",&y);x=y;if(y<0 && x!=y)--x;z=x+(x!=y);            if(i==n && j==n)continue;l[++xb]=x,r[xb]=z;            if(j==n)u[xb]=1,v[xb]=i+1;                else if(i==n)u[xb]=j+n,v[xb]=n<<1;                        else u[xb]=i+1,v[xb]=j+n;        }    for(i=1;i<=xb;++i)out[u[i]]+=l[i],out[v[i]]-=l[i];    for(i=1;i<=n<<1;++i)        if(out[i]>0)g.addedge(i,n*2+2,out[i]),s+=out[i];            else if(out[i])g.addedge(n<<1|1,i,-out[i]);    for(i=1;i<=xb;++i)if(l[i]<r[i])g.addedge(u[i],v[i],r[i]-l[i]);    g.n=n*2+2;    if(g.maxflow(n<<1|1,n*2+2)<s)return puts("No"),0;    printf("%d\n",g.maxflow(1,n<<1)*3);    return 0;}
原创粉丝点击