1. 程式人生 > >網絡流 ek

網絡流 ek

增加 string class 偶數 訪問 -1 add mem code

hdu3549 求最大流果題

ek算法 先bfs出一條流 然後通過不斷地添加增廣路 得到最大流(證明在算法書上都有)

增加了一個流 就加反向邊 允許程序通過走方向邊的方式進行“回滾”

當i>=2時 i^1 = i+1(i為奇數), i^1 = i-1(i為偶數)這樣從二開始 偶數位置放正邊 計數位置放反邊 就可以快速找到邊的逆邊

pre記錄路徑 具體是pre存到達當前點的邊的序號

pre還順便可以記錄點的訪問情況 省去了一個vis數組

每次bfs找到增廣路徑之後 從終點找到起點 找出最小的邊權 就是這次增廣增加的流

就這些

#include<cstdio>
#include
<cstring> #include<queue> using namespace std; const int maxn = 107, maxm = 1007, inf = 0x3f3f3f3f; struct edge{ int u, v, w, nxt; edge(){} edge(int u, int v, int w, int nxt):u(u), v(v), w(w), nxt(nxt){} }e[2*maxm]; int cur, head[maxn], pre[maxn]; void addedge(int u, int v, int w){ e[cur]
= edge(u, v, w, head[u]); head[u] = cur++; e[cur] = edge(v, u, 0, head[v]); head[v] = cur++; } void init(){ cur = 2; memset(head, -1, sizeof(head)); } bool bfs(int st, int ed){ queue<int>Q; memset(pre, -1, sizeof(pre)); Q.push(st); while(!Q.empty()){
int u = Q.front(); Q.pop(); if(u == ed) return true; for(int i = head[u]; ~i; i = e[i].nxt){ int v = e[i].v, w = e[i].w; if(w && pre[v] == -1){ pre[v] = i; Q.push(v); } } } return false; } int ek(int st, int ed){ int ans = 0; while(bfs(st, ed)){ int tmp = ed, det = inf; while(tmp != st){ int edges = pre[tmp]; det = min(det, e[edges].w); tmp = e[edges].u; } tmp = ed; while(tmp != st){ int edges = pre[tmp]; e[edges].w -= det; e[edges^1].w += det; tmp = e[edges].u; } ans += det; } return ans; } int main(){ int t, kase = 0; scanf("%d", &t); while(t--){ init(); int n, m; scanf("%d%d", &n, &m); while(m--){ int x, y, w; scanf("%d%d%d", &x, &y, &w); addedge(x, y, w); } printf("Case %d: ", ++kase); printf("%d\n", ek(1, n)); } return 0; }

網絡流 ek