可行流 : 能流過去就行,不一定是最大流。
最大流:能流到的最大流量。(可能不只一個)
解決最大流:
Ford-Fulkerson方法
最小割:從圖中去除一些邊,使得源點S到匯點T不連通,去除的這些邊權的權和最小,就是最小割
PS!!!這個權和可以證明等於網絡的最大流量!
最大流等價於最小割!!! 求解最大流問題,也可以轉化為最小割
但是求最大流和求最小割集是兩類不同的算法。求解最小割集普遍采用Stoer-Wagner算法
1》》任意割大於等於任意流
從源點到匯點必然經過割邊(必然存在其中一條邊是割邊)那么令S - T的分支流分別為f1,f2,^...fn,f1 + f2 + …… fn = f
(流——你可以少,但不能多,多過這條邊的流限制就錯了,所以,分割S,T集合后,流向T的必然會完全流入T,而割就是如何分割S,T
所以f1<=c1,f2<= c2,f3 <= c3
所以任意可行的割ci + cj + ck >= fi + fj + fk
2》最大流 = 最小割
(思考問題的時候要把每一條邊分離出來看,對於合並的流也應該拆開)
最大流是不能再流了,所以對於每一條分流中,必然存在一條邊 i,使得fi == ci,對於這條邊源頭的流出目的是我要滿足達到ci的流量即為最大流,且fi >= fk(k!=i),所以ci也是最小的容量
所以對於每一個分流,我都會割取最小的容量邊,而又因為是最大流,所以最小容量邊必然滿流,否則必然存在增廣路徑使的當前流變為最大流,所以最小割對應的容量即為最大流
求解最大流算法:
最簡單的FF算法:
當然因為簡單易操作,所以時間復雜度較高,一般不會使用在ACM上,但一切都是以簡單為基礎的
FF算法的思想:
從s到t一直尋找可行最大流量,找到一個,最終的最大流加上它,然后就不找了,回溯,維護正向邊和逆向邊,然后回溯完了,進行適當的初始化后再重新找,直到找不到位置
從我的描述方面就能看出,FF算法做了很多重復性的工作,一條邊一條線可能被掃多次,但是沒有標記這條邊不可行,因為只有邊可行才會維護刪權
接下來是代碼
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
#define inf (1<<28)
using namespace std;
typedef long long ll;
const int maxn = 1e4 + 1e2;
const int maxm = 1e5 + 1e3;
//n個點 m條邊
//從s - t求最大流
int n,m,s,t;
//鏈式前向星存儲
struct node
{
int to,cost,pre;
}e[maxm<<1];
int id[maxn],cnt;
//最大流量ans
ll ans;
//dfs中
bool vis[maxn],flag;
void add(int from,int to,int cost)
{
e[cnt].to = to;
e[cnt].cost = cost;
e[cnt].pre = id[from];
id[from] = cnt++;
}
int dfs(int now,int flow)
{
if(now == t)
{
flag = true;
ans += flow;
return flow;
}
vis[now] = 1;
for(int i = id[now];~i;i = e[i].pre)
{
int to = e[i].to;
int cost = e[i].cost;
if(vis[to] || cost == 0)continue;
int delta = dfs(to,min(flow,cost));
if(flag)
{
e[i].cost -= delta;
e[i^1].cost += delta;
return delta;
}
}
return 0;
}
void FF()
{
flag = false;
memset(vis,0,sizeof(vis));
dfs(s,inf);
while(flag)
{
memset(vis,0,sizeof(vis));
flag = false;
dfs(s,inf);
}
}
void init()
{
memset(id,-1,sizeof(id));
cnt = 0;
ans = 0;
}
int main()
{
while(~scanf("%d%d%d%d",&n,&m,&s,&t))
{
init();
int from,to,cost;
for(int i = 1;i <= m;++i)
{
scanf("%d%d%d",&from,&to,&cost);
add(from,to,cost);
add(to,from,0);
}
FF();
printf("%lld\n",ans);
}
return 0;
}
