有上下界的網路流問題

2021-09-06 16:43:51 字數 3742 閱讀 9282

前幾天就想寫了的,一直沒寫,今天就寫完吧。

因為在做這些上下界的題的時候,遇到了很多問題,在大神的幫助下還是一一解決了的。(英文沒學好誒喂,,在sgu和poj各種wa。。)

主要是沒看題,求上下界已經理解了的。。

做法:將圖的下界分離到乙個附加源和匯中,而上界則變為原弧的上界減去下界的差,構成乙個附加網路,再在附加源匯上跑一次最大流即可。其中,記錄每個點的入流下界和-出流下界和,當下界和》0時怎連入一條源s到這個點的邊,上界為這個下界和,下界為0;當下界和<0則連入一條這個點到匯t的邊,上界為下界和的絕對值,下界為0。

判斷:僅當以源s為起點的弧或以匯t為終點的弧全部流滿,則滿足下界的可行流才存在,否則不存在。

例題:sgu194

**:

#include #include using namespace std;

#define cc(a, c) memset(a, c, sizeof(a))

#define for(i,a,n) for(i=a;i<=n;++i)

const int maxn=500, oo=~0u>>1, maxm=80810;

int s, t, cap[maxm], d[maxn], cur[maxn], gap[maxn], p[maxn];

int n, ihead[maxn], inext[maxm], to[maxm], from[maxm], cnt;

int dn[maxm], du[maxn];

int min(const int& a, const int& b)

int isap()

} return flow;

}void add(int u, int v, int c)

void init(int s, int t, int n)

int main()

for(i=1; i<=n; ++i)

isap();

flag=1;

for(i=ihead[s]; i; i=inext[i]) if(cap[i]) //僅當流滿才存在

if(!flag) puts("no");

else

} return 0;

}

做法:從匯t連一條弧到源s,上界為無限大,下界為0。再設乙個超級源ss和乙個超級匯tt,按照無源匯上下界最大流的方法連邊給ss和tt,從ss跑最大流到tt,判斷是否有弧滿後,去掉超級源和匯及其邊,跑一次s-t的最大流(注意這裡最大流絕不是t-s的反向弧,因為在第二次跑最大流的時候將這弧退掉了),最後根據題目要求輸出即可。

技巧:我用的是鏈式前向星(鄰接表),因此將ss和tt的head去掉即可,為什麼呢,因為這不會影響到後面跑最大流,因為ss和tt本來就不在s-t的增廣路上,但這裡要注意,因為ss和tt還在圖中,因此呼叫最大流的演算法時,點的數量要包括了ss和tt。

例題:zoj3229

ps:這題是我除錯了2天的。。太坑了,很多細節,還是注意看題吧。。比如說按輸入的順序輸出。。導致我演算法沒錯則一直在找演算法的錯誤,還是請大神幫我找出來的。。。。。但是還是找到了一些bug且大神幫我優化了我的sap的乙個地方,還是很感謝他的~

ps:這題樣例是有問題的,請不要相信第乙個case,用第二個case來做測試吧

**:

#include #include using namespace std;

#define cc(a, c) memset(a, c, sizeof(a))

#define for(i,a,n) for(i=a;i<=n;++i)

const int maxn=1510, oo=100000000, maxm=151000;

int cap[maxm], d[maxn], cur[maxn], gap[maxn], p[maxn];

int ihead[maxn], inext[maxm], to[maxm], from[maxm], cnt;

int inout[maxn], down[400][1200], id[400][1200]; //這裡用maxn*maxn的話就mle了。。

int e[maxm][2], e;

int min(const int& a, const int& b)

int isap(int s, int t, int n)

} return flow;

}void add(int u, int v, int c)

void init()

int main()

for(i, 1, n)

} add(t, s, oo); //新增匯到源的oo弧

s=n+m+3; t=n+m+4; //設定超級源和匯

sum=0;

for(i, 1, n+m+2) //sum是判斷滿流的一種方法

if(inout[i]<0) add(i, t, -inout[i]);

} if(isap(s, t, t)!=sum) printf("-1\n");

else

printf("\n");

} return 0;

}

做法:先不連邊t-s,先構造了附加網路到超級源和超級匯中,然後跑超級源到超級匯的最大流,再連匯t到源s上界為無限大下界為0的弧,再跑一次超級源到超級匯的最大流即可,最小流就是t-s的反向弧。。。(ps,這裡我不明白為什麼這樣做,問了之前幫我的大神,他也不知道,因此我先放下吧,以後問問其它大神。。其實我有乙個理解,就是先將之前 上界-下界 的那些弧的最大跑出來, 然後連邊後再跑,其實就是退流,將之前跑的退回去,這樣既滿足了下界限制,又是可行流,因為退流回去的是最大流,因此第二次跑出來的是最小流)

例題:sgu176

**:

#include #include using namespace std;

#define cc(a, c) memset(a, c, sizeof(a))

#define for(i,a,n) for(i=a;i<=n;++i)

const int maxn=1510, oo=100000000, maxm=151000;

int cap[maxm], d[maxn], cur[maxn], gap[maxn], p[maxn];

int ihead[maxn], inext[maxm], to[maxm], from[maxm], cnt;

int inout[maxn], ans[maxm], id[maxm];

int min(const int& a, const int& b)

int isap(int s, int t, int n)

} return flow;

}void add(int u, int v, int c, int _id)

void init()

int main()

e=cnt;

ss=n+1; tt=ss+1;

for(i, 1, n)

isap(ss, tt, tt); //先跑一次最大流

add(t, s, oo, 0); //連邊

isap(ss, tt, tt); //再跑一次最大流

for(i=ihead[ss]; i; i=inext[i]) if(cap[i]) break;

if(i) puts("impossible");

else

} return 0;

}

周源《一種簡易的方法求解流量有上下界的網路中網路流問題》

mr. ant部落格:

有上下界網路流問題

此類問題可以分為三小類問題 一 無源匯有上下界最大流 二 有源匯有上下界最大流 三 有源匯有上下界最小流 1 無源匯有上下界最大流 題目大意 給n個點,及m根pipe,每根pipe用來流躺液體的,單向的,每時每刻每根pipe流進來的物質要等於流出去的物質,要使得m條pipe組成乙個迴圈體,裡面流躺物...

有上下界網路流

前言 下面寫得只是一些十分基礎的東西,是給我以後自己看的,想要徹底弄明白這個內容,推薦去看liu runda。注 為了方便,下面所有的 x,y,l,r 都表示一條從x連向y,流量下界為l,流量上界為r的邊。問題簡述 給出乙個有向圖,每條邊有流量上下界,沒有源點和匯點,要求找到一種流的方法,使得每個點...

有上下界的網路流

有上下界的網路流 這幾天看了周源的 一種簡易的方法求解流量有上下界的網路中網路流問題 並完成了 sgu 194 zoj 2314 reactor cooling,sgu 176 flow construction 和hoj 2135 poj 2396 budget三道題。作為周源文章中提到的求解上下...