網路流 最大流,最小割,費用流問題

2022-05-27 19:06:12 字數 3990 閱讀 3166

例題:

p1231 教輔的組成

p2598 [zjoi2009]狼和羊的故事

p4016 負載平衡問題

貪心流程:

找一條\(s\)到\(t\)的只經過\(f(e)< c(e)\)的邊的路徑。

如果不存在滿足條件的路徑,則演算法結束。否則,沿著該路徑盡可能地增加\(f(e)\),返回第(1)步。這一步驟稱作增廣。

反悔機制:

只利用滿足\(f(e)< c(e)\)的\(e\)或\(f(e)> 0\)的\(e\)的反向邊\(rev(e)\),尋找一條\(s\)到\(t\)的路徑。

如果不存在滿足條件的路徑,則演算法結束。否則,沿著該路徑盡可能地增加流,返回(1)。

核心**:

bool bfs(int s)

} return dis[n1+n2+n1+n3+1];

}int dfs(int x,int limit)

return res;

}int main()

printf("%d\n",ans);

return 0;

}

性質:最小割 = 最大流

在求解最大流時,我們在殘量網路上不斷貪心地增廣而得到了最大流。現在邊上多了費用,為了使最後總費用最小,我們自然能想到每次貪心地在殘量網路上,沿著費用最小的那條路進行增廣,此時殘量網路中的反向邊費用應該是原邊費用的相反數,以保證退流操作是可逆、正確的。

核心**:

bool spfa(int s)

} } }

return dis[t] != inf;

}int main()

int ans1 = 0,ans2 = 0;

while (spfa(s))

printf("%d %d\n",ans1,ans2);

return 0;

}

例題:

對於第一道題,想要盡可能的多組出書的配套方案,我們可以聯想到最大流,那麼問題就在於如何連邊,因為給出的都是書和練習冊,或者書和答案之間的關係,所以我們把書放在中間,練習冊和答案分別和他連邊。

但是這就出現了乙個問題,每本書只能選一次,怎樣才能保證這個問題呢???我們把書拆成兩個點,中間連一條邊權為1的邊就可以解決了。

code:

#include #include #include #include #include using namespace std;

int read()

while (ch >= '0'&&ch <= '9')

return x*a;

}const int maxn = 1e5+10,inf = 1e9+7;

int n1,n2,n3;

int m1,m2;

struct nodeed[maxn*4];

int head[maxn*4],tot = 1,cur[maxn*4];

void add(int u,int to,int w)

int dis[maxn*4];

bool bfs(int s)

} return dis[n1+n2+n1+n3+1];

}int dfs(int x,int limit)

return res;

}int main()

m2 = read();

for (int i = 1;i <= m2;i++)

for (int i = 1;i <= n1;i++)

for (int i = 1;i <= n2;i++) add(0,i,1),add(i,0,0);

for (int i = 1;i <= n3;i++) add(i+n1+n2+n1,n1+n2+n1+n3+1,1),add(n1+n2+n1+n3+1,i+n1+n2+n1,0);

int ans = 0,tmp;

for (int i = 0;i <= n1+n2+n1+n3+1;i++) cur[i] = head[i];

while (bfs(0))

printf("%d\n",ans);

return 0;

}

第二道題主要看我們如何能把問題轉化為最小割,連出乙個四聯通圖後,建立源點和匯點,把羊向源點連邊,狼向匯點連邊,邊權全為\(inf\),這樣我們在求最小割的時候一定不會斷掉他(因為他太大了啊)

正確性:狼和羊能相遇的充分條件是能通過狼和羊亮點從源點走到匯點,如果現在不連通,且斷掉的不是連線源點和匯點這些邊,那麼一定是狼和羊之間的路徑

code:

#include #include #include #include #include using namespace std;

int read()

while (ch >= '0'&&ch <= '9')

return x*a;

}const int maxn = 1000*1000+10,inf = 1e9+7;

int n,m;

int s,t;

struct nodeed[maxn*4];

int head[maxn*4],tot = 1,cur[maxn*4];

void add(int u,int to,int w)

int dis[maxn*4];

bool bfs(int s)

} return dis[t];

}int dfs(int x,int limit)

return res;

}int main()

} int tmp,ans = 0;

for (int i = s;i <= t;i++) cur[i] = head[i];

while (bfs(0))

printf("%d\n",ans);

return 0;

}

第三題而言重點還是在建模,貪心的想,多的我們移走,少的我們補充,正好的我們不動,那麼建邊就分為以下幾種情況:

比平均值大的倉庫,從源點向他連一條流量為\(a_i-sum\)的邊,費用為0,說明要從他移出

比平均值小的倉庫,從他向匯點連一條流量為\(sum-a_i\)的邊,費用為0,說明要補充他

相鄰倉庫間建一條流量為\(inf\),費用為1的邊,可以無限移動,但是與源點匯點連的邊限制了他們

code:

#include #include #include #include #include using namespace std;

int read()

while (ch >= '0'&&ch <= '9')

return x*a;

}const int maxn = 500,inf = 1e9+7;

int n,a[maxn],s,t;

struct nodeed[maxn*4];

int head[maxn*4],tot = 1;

void add(int u,int to,int lim,int w)

int vis[maxn],dis[maxn],pre1[maxn],pre2[maxn];

bool spfa(int s)

}} }

return dis[t] != inf;

}int main()

add(1,n,inf,1),add(n,1,0,-1);

add(n,1,inf,1),add(1,n,0,-1);

int ans = 0;

while (spfa(s))

printf("%d\n",ans);

return 0;

}

網路流 費用流 最大流最小割定理

囧,今天第一天電腦競賽補課,就把最大流的bfs增廣 先流預推法 最大流最小割定理 最小費用流講完了。汗。而我,就只記住了bfs增廣和最大流最小割定理。最小費用流ms差不多明白了。所以先講講bfs增廣求最大流的演算法吧。簡單的來說,就是從s 源 開始bfs,直到到達t 匯 or不存在增廣路。所謂增廣路...

網路流 費用流 最大流最小割定理

囧,今天第一天電腦競賽補課,就把最大流的bfs增廣 先流預推法 最大流最小割定理 最小費用流講完了。汗。而我,就只記住了bfs增廣和最大流最小割定理。最小費用流ms差不多明白了。所以先講講bfs增廣求最大流的演算法吧。簡單的來說,就是從s 源 開始bfs,直到到達t 匯 or不存在增廣路。所謂增廣路...

網路流 最大流 最小割 最小費用流

sap gap 鄰接表 sap gap 鄰接矩陣 dinic 鄰接矩陣 dinic 鄰接表 介個人寫的敲詳細 include include include include include using namespace std const int maxn 5010 const int maxn ...