• Flow construction SGU


    /**
    
    题目:Flow construction SGU - 176
    链接:https://vjudge.net/problem/SGU-176
    题意:
    有源汇有上下界的最小流。
    给定n个点,m个管道。每个管道给出u,v,z,c。u表示起点,v表示终点,z表示容量,如果c==1,那么表示还有下界为z。
    如果c==0,表示没有下界。
    求从1到n的最小流。
    思路:
    第一种做法:
    转化为无源汇求超级源S到超级汇T的最大流flow1(此时从s出发的流和为flow1),然后讲t到s的边删掉(可以使流量等于容量,这样求t到s的最大流就不会经过他了。)
    求t到s的最大流flow2(从s出发的流减少的量).是为了回流,因为原先求flow1的过程,是为了满足下界的可行流。这个在原图的可行流可能可以变得更小,通过回流使其缩小。
    求t到s的最大流并不会影响原来附加边的流量。所以保证了是下界满足的可行流。
    然后用flow1-flow2就是结果。
    
    第二种做法:
    构造无源汇有上下界的可行流做法,只不过t到s的边的上下界要改一下。
    二分t到s的上界a,下界为0,如果是可行流最小的a便是最小流。如果是求最大流,那么就是二分t到s的下界a,上界无穷,如果是可行流,那么最大的a便是最大流。
    不懂的看文档解释。https://wenku.baidu.com/view/0f3b691c59eef8c75fbfb35c.html
    
    
    关于每次二分,处理一次最大流,那么下次在计算最大流的时候,难道又要重新建图?
    反正是结构体存的,新加一个变量存储。下次直接从这个变量获取即可。注意t到s这条边的修改。或者最后面再加进去。
    
    
    */
    
    第一种做法
    
    #include<iostream>
    #include<cstring>
    #include<vector>
    #include<map>
    #include<cstdio>
    #include<algorithm>
    #include<queue>
    using namespace std;
    const int INF = 0x3f3f3f3f;
    typedef long long LL;
    const int N = 210;///n+m=1365
    int in[N];
    int out[N];
    struct Edge{
        int from, to, cap, flow;
        Edge(int u,int v,int c,int f):from(u),to(v),cap(c),flow(f){}
    };
    struct Dinic{
        int n, m, s, t;
        vector<Edge> edges;
        vector<int> G[N];
        bool vis[N];
        int d[N];
        int cur[N];
    
        void init(int n)
        {
            this->n = n;
            for(int i = 0; i <= n; i++) G[i].clear();
            edges.clear();
        }
    
        void AddEdge(int from,int to,int cap)
        {
            edges.push_back(Edge(from,to,cap,0));
            edges.push_back(Edge(to,from,0,0));
            m = edges.size();
            G[from].push_back(m-2);
            G[to].push_back(m-1);
        }
    
        bool BFS()
        {
            memset(vis, 0, sizeof vis);
            queue<int> Q;
            Q.push(s);
            d[s] = 0;
            vis[s] = 1;
            while(!Q.empty())
            {
                int x = Q.front();
                Q.pop();
                for(int i = 0; i < G[x].size(); i++)
                {
                    Edge &e = edges[G[x][i]];
                    if(!vis[e.to]&&e.cap>e.flow)
                    {
                        vis[e.to] = 1;
                        d[e.to] = d[x]+1;
                        Q.push(e.to);
                    }
                }
            }
            return vis[t];
        }
    
        int DFS(int x,int a)
        {
            if(x==t||a==0) return a;
            int flow = 0, f;
            for(int &i = cur[x]; i < G[x].size(); i++)
            {
                Edge& e = edges[G[x][i]];
                if(d[x]+1==d[e.to]&&(f=DFS(e.to,min(a,e.cap-e.flow)))>0)
                {
                    e.flow += f;
                    edges[G[x][i]^1].flow -= f;
                    flow += f;
                    a -= f;
                    if(a==0) break;
                }
            }
            return flow;
        }
    
        int Maxflow(int s,int t)
        {
            this->s = s, this->t = t;
            int flow = 0;
            while(BFS())
            {
                memset(cur, 0, sizeof cur);
                flow += DFS(s,INF);
            }
            return flow;
        }
    };
    int dw[N*N];
    int main()
    {
        int n, m;
        while(scanf("%d%d",&n,&m)==2)
        {
            Dinic dinic;
            dinic.init(n+1);
            int u, v, cap, flag;///1,n为普通源汇。
            int s = 0, t = n+1;///超级源汇。
            memset(dw, 0, sizeof dw);
            memset(in, 0, sizeof in);
            memset(out, 0, sizeof out);
            for(int i = 0; i<m; i++){
                scanf("%d%d%d%d",&u,&v,&cap,&flag);
                if(flag==1){
                    dw[i] = cap;
                    dinic.AddEdge(u,v,0);
                    out[u]+=cap;
                    in[v]+=cap;
                }else
                {
                    dinic.AddEdge(u,v,cap);
    
                }
            }
            int ts;
            dinic.AddEdge(n,1,INF);
            ts = dinic.edges.size()-2;
            int sum = 0;
            for(int i = 1; i <= n; i++){
                if(in[i]>out[i]){
                    dinic.AddEdge(s,i,in[i]-out[i]);
                    sum += in[i]-out[i];
                }
                if(in[i]<out[i]){
                    dinic.AddEdge(i,t,out[i]-in[i]);
                }
            }
            int flow = dinic.Maxflow(s,t);
            if(flow!=sum){
                printf("Impossible
    "); continue;
            }
            dinic.edges[ts].cap = dinic.edges[ts].flow;///使其求n到1的最大流无法经过。
            int flow2 = dinic.Maxflow(n,1);///回流
            printf("%d
    ",flow-flow2);
            for(int i = 0; i < m; i++){
                if(i==m-1){
                    printf("%d
    ",dinic.edges[2*i].flow+dw[i]);
                }else
                {
                    printf("%d ",dinic.edges[2*i].flow+dw[i]);
                }
            }
        }
        return 0;
    }
    
    
    第二种做法
    
    #include<iostream>
    #include<cstring>
    #include<vector>
    #include<map>
    #include<cstdio>
    #include<algorithm>
    #include<queue>
    using namespace std;
    const int INF = 0x3f3f3f3f;
    typedef long long LL;
    const int N = 210;///n+m=1365
    int in[N];
    int out[N];
    struct Edge{
        int from, to, cap, flow;
        Edge(int u,int v,int c,int f):from(u),to(v),cap(c),flow(f){}
    };
    struct Dinic{
        int n, m, s, t;
        vector<Edge> edges;
        vector<int> G[N];
        bool vis[N];
        int d[N];
        int cur[N];
    
        void init(int n)
        {
            this->n = n;
            for(int i = 0; i <= n; i++) G[i].clear();
            edges.clear();
        }
    
        void AddEdge(int from,int to,int cap)
        {
            edges.push_back(Edge(from,to,cap,0));
            edges.push_back(Edge(to,from,0,0));
            m = edges.size();
            G[from].push_back(m-2);
            G[to].push_back(m-1);
        }
    
        bool BFS()
        {
            memset(vis, 0, sizeof vis);
            queue<int> Q;
            Q.push(s);
            d[s] = 0;
            vis[s] = 1;
            while(!Q.empty())
            {
                int x = Q.front();
                Q.pop();
                for(int i = 0; i < G[x].size(); i++)
                {
                    Edge &e = edges[G[x][i]];
                    if(!vis[e.to]&&e.cap>e.flow)
                    {
                        vis[e.to] = 1;
                        d[e.to] = d[x]+1;
                        Q.push(e.to);
                    }
                }
            }
            return vis[t];
        }
    
        int DFS(int x,int a)
        {
            if(x==t||a==0) return a;
            int flow = 0, f;
            for(int &i = cur[x]; i < G[x].size(); i++)
            {
                Edge& e = edges[G[x][i]];
                if(d[x]+1==d[e.to]&&(f=DFS(e.to,min(a,e.cap-e.flow)))>0)
                {
                    e.flow += f;
                    edges[G[x][i]^1].flow -= f;
                    flow += f;
                    a -= f;
                    if(a==0) break;
                }
            }
            return flow;
        }
    
        int Maxflow(int s,int t)
        {
            this->s = s, this->t = t;
            int flow = 0;
            while(BFS())
            {
                memset(cur, 0, sizeof cur);
                flow += DFS(s,INF);
            }
            return flow;
        }
    };
    int dw[N*N];
    int main()
    {
        int n, m;
        while(scanf("%d%d",&n,&m)==2)
        {
            Dinic dinic;
            dinic.init(n+1);
            int u, v, cap, flag;///1,n为普通源汇。
            int s = 0, t = n+1;///超级源汇。
            memset(dw, 0, sizeof dw);
            memset(in, 0, sizeof in);
            memset(out, 0, sizeof out);
            for(int i = 0; i<m; i++){
                scanf("%d%d%d%d",&u,&v,&cap,&flag);
                if(flag==1){
                    dw[i] = cap;
                    dinic.AddEdge(u,v,0);
                    out[u]+=cap;
                    in[v]+=cap;
                }else
                {
                    dinic.AddEdge(u,v,cap);
    
                }
            }
            int sum = 0;
            for(int i = 1; i <= n; i++){
                if(in[i]>out[i]){
                    dinic.AddEdge(s,i,in[i]-out[i]);
                    sum += in[i]-out[i];
                }
                if(in[i]<out[i]){
                    dinic.AddEdge(i,t,out[i]-in[i]);
                }
            }
            Dinic Tdinic = dinic;
            int flow;
            int lo = 0, hi = INF, mid;
            while(lo<hi){///最小流,二分上界,取最小值。
                mid = (lo+hi)/2;
                dinic = Tdinic;
                dinic.AddEdge(n,1,mid);
                flow = dinic.Maxflow(s,t);
                if(flow!=sum){
                    lo = mid+1;
                }else
                {
                    hi = mid;
                }
            }
            if(hi==lo){
                printf("Impossible
    "); continue;
            }
            printf("%d
    ",hi);
            dinic = Tdinic;///注意复原,因为此时的dinic不是最小流为hi的时候的。要重新计算。
            dinic.AddEdge(n,1,hi);
            dinic.Maxflow(s,t);
            for(int i = 0; i < m; i++){
                if(i==m-1){
                    printf("%d
    ",dinic.edges[2*i].flow+dw[i]);
                }else
                {
                    printf("%d ",dinic.edges[2*i].flow+dw[i]);
                }
            }
        }
        return 0;
    }
  • 相关阅读:
    蛙蛙推荐:微软MSDN导航菜单演示(Javascript+CSS2)
    看来偶的WEB软件开发基本功还得再扎实一些
    蛙蛙请教:c#面向对象编程的有些抉择问题?
    蛙蛙请教:偶在CSDN发的好多问题都没有解决呢,我集中了一下,大家给看看
    Hive UDF开发
    ubuntu下设置开机自启动项
    ubuntu 扩展存储空间
    ubuntu 快速回到桌面
    编译Hive/Hadoop总结
    Linux MC——终端环境的文件管理器
  • 原文地址:https://www.cnblogs.com/xiaochaoqun/p/7201731.html
Copyright © 2020-2023  润新知