有上下界的最大流解法

來源:互聯網
上載者:User

標籤:c++

問題模型:

給定一個加權的有向圖,滿足:

(1)容量限制條件:

              

(2)流量平衡條件:

             

(2)中的即除了源匯外,所有點都滿足流量平衡條件,則稱G為有源匯網路;否則,即不存在源匯,所有點都滿足流量平衡條件,則稱G為無源匯網路。

將這類問題由易到難一一解決:

問題[1] 求無源匯的網路有上下界的可行流

由於下界是一條弧上的流必需要滿足的確定值。下面引入必要弧的概念:必要弧是一定流要滿的弧。必要弧的構造,將容量下界的限制分離開了,從而構造了一個沒有下界的網路G’:

1. 將原弧(u,v)分離出一條必要弧:。(紅色表示)

2. 原弧:。


由於必要弧的有一定要滿的限制,將必要弧“拉”出來集中考慮:


添加附加源x, 附加匯y。想像一條不限上界的(y, x),用必要弧將它們“串”起來,即對於有向必要弧(u, v),添加(u, y),(x, v),容量為必要弧容量。這樣就建立了一個等價的網路。


一個無源匯網路的可行流的方案一定是必要弧是滿的。若去掉(y, x)後,附加源x到附加匯y的最大流,能使得x的出弧或者y的入弧都滿,充要於原圖有可行流。


問題[2] 求無源匯的網路有上下界的可行流

演算法:

1. 按上述方法構造新網路(分離必要弧,附加源匯)

2. 求附加源x到附加匯y的最大流

3. 若x的出弧或y的入弧都滿,則有解,將必要弧合并回原圖;否則,無解。



zoj2314(無源匯點 有上下界  可行流的判斷)

代碼:

#include <iostream>#include <cstring>#include <cstdio>#include <algorithm>#include <queue>const int MAXN =505;const int MAXM=440020;const int INF=0x3f3f3f3f;using namespace std;struct Edge {    int to,cap,flow,next;} edge[MAXM];int head[MAXN],tot,gap[MAXN],d[MAXN],cur[MAXN],que[MAXN],p[MAXN];int n;int id[MAXM];void init(){    tot=0;    memset(head,-1,sizeof(head));}void addedge(int u,int v,int c,int d){    edge[tot]=(Edge){v,c,0,head[u]};    id[d]= head[u] = tot++;    edge[tot]=(Edge){u,c,c,head[v]};    head[v] = tot++;}int isap(int source,int sink,int N){    memset(gap,0,sizeof(gap));    memset(d,0,sizeof(d));    memcpy(cur,head,sizeof(head));    int top = 0,x = source,flow = 0;    while(d[source] < N) {        if(x == sink) {            int Min = INF,inser=0;            for(int i = 0; i < top; ++i) {                if(Min > edge[p[i]].cap - edge[p[i]].flow) {                    Min = edge[p[i]].cap - edge[p[i]].flow;                    inser = i;                }            }            for(int i = 0; i < top; ++i) {                edge[p[i]].flow += Min;                edge[p[i]^1].flow -= Min;            }            if(Min!=INF) flow += Min;            top = inser;            x = edge[p[top]^1].to;            continue;        }        int ok = 0;        for(int i = cur[x]; i != -1; i = edge[i].next) {            int v = edge[i].to;            if(edge[i].cap > edge[i].flow && d[v]+1 == d[x]) {                ok = 1;                cur[x] = i;                p[top++] = i;                x = edge[i].to;                break;            }        }        if(!ok) {            int Min = N;            for(int i = head[x]; i != -1; i = edge[i].next) {                if(edge[i].cap > edge[i].flow && d[edge[i].to] < Min) {                    Min = d[edge[i].to];                    cur[x] = i;                }            }            if(--gap[d[x]] == 0) break;            gap[d[x] = Min+1]++;            if(x != source) x = edge[p[--top]^1].to;        }    }    return flow;}int main(){//    freopen("in.txt","r",stdin);    int T,m,ss;    int a,b,low,up;    int d[MAXN];    int l[MAXM];    scanf("%d",&T);    while(T--)    {        init();        memset(d,0,sizeof(d));        ss=0;        scanf("%d%d",&n,&m);        for(int i=1;i<=m;i++)        {            scanf("%d%d%d%d",&a,&b,&low,&up);            addedge(a,b,up-low,i);            d[a]+=low;            d[b]-=low;            l[i]=low;        }        for(int i=1;i<=n;i++)        {            if(d[i]>0){                addedge(i,n+1,d[i],0);                ss+=d[i];            }            else                addedge(0,i,-d[i],0);        }        if(isap(0,n+1,n+2)==ss){            printf("YES\n");            for(int i=1;i<=m;i++)                         //最後輸出可行流                printf("%d\n",edge[id[i]].flow+l[i]);        }        else            printf("NO\n");    }    return 0;}







問題[2] 求有源匯的網路有上下界的可行流


加入邊(t, s),下界為0(保證不會連上附加源匯x, y),不限上界,將問題[2]轉化為問題[1]來求解。







問題[3]求有源匯的網路有上下界的最大流

演算法:

1. 先轉化為問題[2]來求解一個可行流。若可行無解,則退出。由於必要弧是分離出來的,所以就可以把必要弧(附加源匯及其臨邊)及其上的流,暫時刪去。再將(T,S)刪去,恢複源匯。

2. 再次,從S到T找增廣軌,求最大流。

3. 最後將暫時刪去的下界資訊恢複,合并到當前圖中。輸出解。

這樣既不破壞下界(分離出來)也不超出上界(第2步滿足容量限制),問題解決。





問題[4]求有源匯的網路有上下界的最小流

演算法:

1. 同問題[3]。

2. 從T到S找增廣軌,不斷反著改進。

3. 同問題[3]。

問題[3]與問題[4]的另一種簡易求法:

注意問題[2]中,構造出的(t, s),上下界幾乎沒什麼限制。下面看看它的性質:

定理:如果從s到t有一個流量為a的可行流f,那麼從t到s連一條弧(t, s),其流量下界b(t, s) = a,則這個圖一定有一個無源匯的可行流:除了弧(t, s)的容量為a外,其餘邊的容量與f相同。

證明:如果從s到t的最大流量為amax,那麼從t到s連一條下界b(t, s) = a’ > amax的弧(t, s),則從在這個改造後的圖中一定沒有無源匯的可行流:否則將這個可行流中的弧(t, s)除去,就得到了原圖中s到t的流量為a’的流,大於最大流量amax,產生矛盾。

可以二分枚舉這個參數a,即下界b(t, s),每次用問題[1]判斷是否有可行流。這樣就可以求出最大流。

同理,問題[4]要求最小流,只要二分枚舉上界c(t, s)即可。

因為樸素的預流推進演算法O(N3),總複雜度為O(N3 log2流量) 。

思路:

無源匯 (附加源匯+最大解決)

有源匯 (附加(T,S)->無源匯)

著作權聲明:本文為博主原創文章,未經博主允許不得轉載。

有上下界的最大流解法

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.