Skip to Content

Flujo máximo - método Push-relabel mejorado

Modificaremos el método Push-relabel para lograr un mejor tiempo de ejecución.

Descripción

La modificación es extremadamente simple: En el artículo anterior elegíamos un vértice con exceso sin ninguna regla particular. Pero resulta que, si siempre elegimos los vértices con la mayor altura y aplicamos sobre ellos las operaciones push y relabel, entonces la complejidad mejora. Además, para seleccionar los vértices con la mayor altura en realidad no necesitamos ninguna estructura de datos: simplemente guardamos los vértices con la mayor altura en una lista, y recalculamos la lista una vez que todos ellos fueron procesados (entonces se agregarán a la lista vértices con altura ya menor), o cada vez que aparece un nuevo vértice con exceso y una altura mayor (después de reetiquetar un vértice).

A pesar de la simplicidad, esta modificación reduce mucho la complejidad. Para ser precisos, la complejidad del algoritmo resultante es O(VE+V2E)O(V E + V^2 \sqrt{E}), que en el peor caso es O(V3)O(V^3).

Esta modificación fue propuesta por Cheriyan y Maheshwari en 1989.

Implementación

const int inf = 1000000000; int n; vector<vector<int>> capacity, flow; vector<int> height, excess; void push(int u, int v) { int d = min(excess[u], capacity[u][v] - flow[u][v]); flow[u][v] += d; flow[v][u] -= d; excess[u] -= d; excess[v] += d; } void relabel(int u) { int d = inf; for (int i = 0; i < n; i++) { if (capacity[u][i] - flow[u][i] > 0) d = min(d, height[i]); } if (d < inf) height[u] = d + 1; } vector<int> find_max_height_vertices(int s, int t) { vector<int> max_height; for (int i = 0; i < n; i++) { if (i != s && i != t && excess[i] > 0) { if (!max_height.empty() && height[i] > height[max_height[0]]) max_height.clear(); if (max_height.empty() || height[i] == height[max_height[0]]) max_height.push_back(i); } } return max_height; } int max_flow(int s, int t) { height.assign(n, 0); height[s] = n; flow.assign(n, vector<int>(n, 0)); excess.assign(n, 0); excess[s] = inf; for (int i = 0; i < n; i++) { if (i != s) push(s, i); } vector<int> current; while (!(current = find_max_height_vertices(s, t)).empty()) { for (int i : current) { bool pushed = false; for (int j = 0; j < n && excess[i]; j++) { if (capacity[i][j] - flow[i][j] > 0 && height[i] == height[j] + 1) { push(i, j); pushed = true; } } if (!pushed) { relabel(i); break; } } } return excess[t]; }