• sgu176 有源汇上下界最小流


    题意:有一堆点和边,1起点,n终点,某些边有可能必须满流,要求满足条件的最小流

    解法:按原图建边,满流的即上下界都是容量,但是这样按有源汇上下界可行流求出来的可能不是最小流,那么我们需要开始建边的时候不要建从t到s的边,先跑一边从ss到tt的最大流,然后把该边加上再跑一次从ss到tt的最大流,那么从t到s的反向边流过的流量就是原图的最小流,为什么是这样呢,这是因为当我们第一遍跑最大流的时候,此时没有t到s的这条边,那么图中的流量会尽量按其他的边流,当我们第二次跑最大流的时候,流出来的都是第一次中已经无法流到终点的流量,此时再跑最大流时我们就尽量减少了t到s这条边上的流量,实际上可以看成延迟t到s的增流

    #include<bits/stdc++.h>
    #define fi first
    #define se second
    #define mp make_pair
    #define pb push_back
    #define pii pair<int,int>
    #define C 0.5772156649
    #define pi acos(-1.0)
    #define ll long long
    #define mod 1000000007
    #define ls l,m,rt<<1
    #define rs m+1,r,rt<<1|1
    
    using namespace std;
    
    const double g=10.0,eps=1e-12;
    const int N=100+10,maxn=10000+10,inf=0x3f3f3f3f;
    
    struct edge{
        int from,to,Next,c,low;
    }e[maxn<<2];
    int cnt,head[N];
    int dis[N];
    int in[N],out[N];
    void add(int u,int v,int c,int low)
    {
        out[u]+=low;
        in[v]+=low;
        e[cnt].from=u;
        e[cnt].to=v;
        e[cnt].c=c;
        e[cnt].low=low;
        e[cnt].Next=head[u];
        head[u]=cnt++;
        e[cnt].from=v;
        e[cnt].to=u;
        e[cnt].c=0;
        e[cnt].low=low;
        e[cnt].Next=head[v];
        head[v]=cnt++;
    }
    bool bfs(int s,int t)
    {
        memset(dis,-1,sizeof dis);
        dis[s]=0;
        queue<int>q;
        q.push(s);
        while(!q.empty())
        {
            int x=q.front();
            q.pop();
            if(x==t)return 1;
            for(int i=head[x];~i;i=e[i].Next)
            {
                int te=e[i].to;
                if(dis[te]==-1&&e[i].c>0)
                {
                    dis[te]=dis[x]+1;
                    q.push(te);
                }
            }
        }
        return 0;
    }
    int dfs(int x,int mx,int t)
    {
        if(x==t)return mx;
        int flow=0;
        for(int i=head[x];~i;i=e[i].Next)
        {
            int te=e[i].to,f;
            if(e[i].c>0&&dis[te]==dis[x]+1&&(f=dfs(te,min(mx-flow,e[i].c),t)))
            {
                e[i].c-=f;
                e[i^1].c+=f;
                flow+=f;
            }
        }
        if(!flow)dis[x]=-2;
        return flow;
    }
    int maxflow(int s,int t)
    {
        int ans=0,f;
        while(bfs(s,t))
        {
            while((f=dfs(s,inf,t)))ans+=f;
        }
        return ans;
    }
    void init()
    {
        cnt=0;
        memset(head,-1,sizeof head);
        memset(in,0,sizeof in);
        memset(out,0,sizeof out);
    }
    int main()
    {
        ios::sync_with_stdio(false);
        cin.tie(0);
        int n,m;
        while(cin>>n>>m)
        {
            init();
            int s=1,t=n;
            for(int i=1;i<=m;i++)
            {
                int a,b,c,d;
                cin>>a>>b>>c>>d;
                if(d)add(a,b,0,c);
                else add(a,b,c,0);
            }
            int ss=n+1,tt=n+2;
            int sum=0;
            for(int i=1;i<=n;i++)
            {
              //  cout<<in[i]<<" "<<out[i]<<endl;
                if(in[i]>out[i])sum+=in[i]-out[i],add(ss,i,in[i]-out[i],0);
                else add(i,tt,out[i]-in[i],0);
            }
            int flow=maxflow(ss,tt);
            add(t,s,inf,0);
            flow+=maxflow(ss,tt);
            if(sum!=flow)cout<<"Impossible"<<endl;
            else
            {
                cout<<e[cnt-1].c<<endl;
                for(int i=0;i<2*m;i+=2)
                    cout<<e[i^1].c+e[i].low<<" ";
                cout<<endl;
            }
        }
        return 0;
    }
    /********************
    
    ********************/
    View Code
  • 相关阅读:
    leetcode 451 根据字符出现频率排序
    leetcode 1833 雪糕的最大数量
    leetcode 166 Excel表列名称
    877 石子游戏
    01 背包问题
    正则表达式
    leetcode 160 相交链表
    git 备忘录
    leetcode 525 连续数组
    Mysite
  • 原文地址:https://www.cnblogs.com/acjiumeng/p/7810164.html
Copyright © 2020-2023  润新知