最小費用流模板(zkw與spfa)

2022-05-07 01:03:07 字數 2944 閱讀 9351

實踐中, 上面的這個演算法非常奇怪. 在某一些圖上, 演算法速度非常快,

另一些圖上卻比純 spfa 增廣的演算法慢. 不少同學經過實測總結的結果是稠密圖上比較快,

稀疏圖上比較慢, 但也不盡然. 這裡我從理論上分析一下, 究竟這個演算法用於哪些圖可以得到理想的效果.

先分析演算法的增廣流程. 和 spfa 直接演算法相比, 由於同屬於沿最短路增廣的演算法,

實際進行的增流操作並沒有太多的區別, 每次的增流路徑也大同小異. 因此不考慮多路增廣時,

增廣次數應該基本相同. 執行時間上主要的差異應當在於如何尋找增流路徑的部分.

那麼 zkw 演算法的優勢在於**呢?

與 spfa 相比, km 的重標號方式明顯在速度上佔優, 每次只是乙個對邊的掃瞄操作而已.

而 spfa 需要維護較為複雜的標號和佇列操作, 同時為了修正標號, 需要不止一次地訪問某些節點, 速度會慢不少.

另外, 在 zkw 演算法中, 增廣是多路進行的, 同時可能在一次重標號後進行多次增廣.

這個特點可以在許多路徑都費用相同的時候派上用場, 進一步減少了重標號的時間耗費.

下面想一想 zkw 演算法的劣勢, 也就是 km 重標號方式存在的問題.

km 重標號的主要問題就是, 不保證經過一次重標號之後能夠存在增廣路.

最差情況下, 一次只能在零權網路中增加一條邊而已. 這時演算法就會反覆重標號,

反覆嘗試增廣而次次不能增廣, 陷入弄巧成拙的境地.

接下來要說什麼, 大家可能已經猜到了. 對於最終流量較大, 而費用取值範圍不大的圖,

或者是增廣路徑比較短的圖 (如二分圖), zkw 演算法都會比較快. 原因是充分發揮優勢.

比如流多說明可以同一費用反覆增廣, 費用窄說明不用改太多距離標號就會有新增廣路,

增廣路徑短可以顯著改善最壞情況, 因為即使每次就只增加一條邊也可以很快湊成最短路.

如果恰恰相反, 流量不大, 費用不小, 增廣路還較長, 就不適合 zkw 演算法了.

費用流板題:luogup3381 【模板】最小費用最大流

zkw版/板:

#include using namespace std;

void read(int &num)

const int maxn = 5005;

const int maxm = 50005;

const int inf = 1e9;

int n, m, s, t, ans;

int cnt = 1, fir[maxn], nxt[maxm*2], to[maxm*2], c[maxm*2], w[maxm*2];

int dis[maxn];

bool vis[maxn];

void add(int u, int v, int cc, int wt)

int aug(int u, int flow)

int used = 0, delta = 0;

vis[u] = true;

for(int i = fir[u]; i; i = nxt[i])

if(!vis[to[i]] && c[i] && dis[u] == dis[to[i]] + w[i])

return used;

}bool update()

int cost_flow()

while(tmp=aug(s, inf));

}while(update());

return flow;

}int main ()

int max_flow = cost_flow();

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

}

spfa版:

#include using namespace std;

void read(int &num)

const int maxn = 5005;

const int maxm = 50005;

const int inf = 1e9;

int n, m, s, t, ans;

int cnt = 1, fir[maxn], nxt[maxm*2], to[maxm*2], c[maxm*2], w[maxm*2];

int dis[maxn];

bool vis[maxn];

void add(int u, int v, int cc, int wt)

bool spfa(int s, int t)

}vis[u] = 0;

}return dis[s] < inf;

}int aug(int u, int flow)

int used = 0, delta = 0;

vis[u] = true;

for(int i = fir[u]; i; i = nxt[i])

if(!vis[to[i]] && c[i] && dis[u] == dis[to[i]] + w[i])

return used;

}int cost_flow()

}return flow;

}int main ()

int max_flow = cost_flow();

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

}

最小費用流模板

想看更多模板?和最大流模板對比著看 最大流模板 dinic 貼上最小費用流模板 const int oo 1e9 const int mm 11111111 const int mn 888888 int node,src,dest,edge int ver mm flow mm cost mm n...

模板)最小費用流

最大流 spfa結合體,小心即可。include include include include include include using namespace std struct edge vector g 5010 int dis 5010 prevv 5010 preve 5010 n,m,...

模板 最小費用流

最小費用流 在網路中為每條邊加上乙個費用,當流量固定為f時費用的最小值。模板一 通過bellman ford演算法計算最短路,並且沿著最短路增廣。時間複雜度為 o f v e const int maxn 1010,inf 0x3f3f3f3f struct edge int n,dist maxn...