★ zoj 2314 无源汇上下界可行流

来源:互联网 发布:光敏刻章机软件下载 编辑:程序博客网 时间:2024/06/05 08:08

无源汇上下界可行流建图:

1、对于每一条边(u,v,x,y)建边add(u,v,y-x)

2、新建源点S,汇点T,对于in[i]>0,add(S,i,in[i]),对于in[i]<0,add(i,T,-in[i])

3、跑一遍最大流看ans是否等于sum即可


代码:

//Isap算法,复杂度O(n^2m)#pragma comment(linker,"/STACK:102400000,102400000")#include <iostream>#include <string.h>#include <stdio.h>#include <algorithm>#include <vector>#include <string>#include <math.h>#include <queue>#include <stack>#include <map>#include <set>using namespace std;typedef long long ll;   //记得必要的时候改成无符号const int maxn=505;const int maxm=1000005;const int INF=1000000000;struct EdgeNode{    int from;    int to;    int cap;    int cost;    int next;}edge[maxm];int head[maxn],cnt;void add(int x,int y,int z){    edge[cnt].from=x;edge[cnt].to=y;edge[cnt].cap=z;edge[cnt].cost=z;edge[cnt].next=head[x];head[x]=cnt++;    edge[cnt].from=y;edge[cnt].to=x;edge[cnt].cap=0;edge[cnt].cost=0;edge[cnt].next=head[y];head[y]=cnt++;}void init(){    cnt=0;    memset(head,-1,sizeof(head));}int S,T,n,m;int d[maxn],gap[maxn],curedge[maxn],pre[maxn];//curedge[]为当前弧数组,pre为前驱数组int sap(int S,int T,int n){    int cur_flow,flow_ans=0,u,tmp,neck,i;    memset(d,0,sizeof(d));    memset(gap,0,sizeof(gap));    memset(pre,-1,sizeof(pre));    for(i=0;i<=n;i++)curedge[i]=head[i]; //初始化当前弧为第一条邻接表    gap[0]=n;    u=S;    while(d[S]<n)             //当d[S]>=n时,网络中肯定出现了断层    {        if(u==T)        {            cur_flow=INF;            for(i=S;i!=T;i=edge[curedge[i]].to)            {                           //增广成功,寻找瓶颈边                if(cur_flow>edge[curedge[i]].cost)                {                    neck=i;                    cur_flow=edge[curedge[i]].cost;                }            }            for(i=S;i!=T;i=edge[curedge[i]].to)            {                             //修改路径上的边容量                tmp=curedge[i];                edge[tmp].cost-=cur_flow;                edge[tmp^1].cost+=cur_flow;            }            flow_ans+=cur_flow;            u=neck;                     //下次增广从瓶颈边开始        }        for(i=curedge[u];i!=-1;i=edge[i].next)            if(edge[i].cost&&d[u]==d[edge[i].to]+1)               break;        if(i!=-1)        {            curedge[u]=i;            pre[edge[i].to]=u;            u=edge[i].to;        }        else        {            if(0==--gap[d[u]])break;    //gap优化            curedge[u]=head[u];            for(tmp=n,i=head[u];i!=-1;i=edge[i].next)                if(edge[i].cost)                   tmp=min(tmp,d[edge[i].to]);            d[u]=tmp+1;            ++gap[d[u]];            if(u!=S)u=pre[u];           //重标号并且从当前点前驱重新增广        }    }    return flow_ans;}int in[maxn];int low[maxm],id[maxm];int main(){    int t,i,x,y,l,r,sum,ans;    scanf("%d",&t);    while(t--){        scanf("%d%d",&n,&m);        memset(in,0,sizeof(in));        init(); sum=0;        S=0; T=n+1;        for(i=1;i<=m;i++){            scanf("%d%d%d%d",&x,&y,&l,&r);            add(x,y,r-l);            in[y]+=l;            in[x]-=l;            id[i]=cnt-2;            low[cnt-2]=l;        }        for(i=1;i<=n;i++){            if(in[i]>0)add(S,i,in[i]),sum+=in[i];            if(in[i]<0)add(i,T,-in[i]);        }        n=T+1;        ans=sap(S,T,n);        if(ans!=sum)printf("NO\n");        else{            printf("YES\n");            for(i=1;i<=m;i++)            {                printf("%d\n",edge[id[i]].cap-edge[id[i]].cost+low[id[i]]);            }        }    }    return 0;}



0 0