学线性规划的时候发现不能三分钟费用流,而且我之前的模板很丑,于是搞搞,顺便写下没怎么写过的 zkw 费用流。

封装了一下。

最大流

bfs 搜出分层图,dfs 找增广路。

	struct NetworkFlow {
		const int inf = 707406378;
		int S, T;
		int head[N], tot = 1;
		struct Edge {
			int to; ll w; int op, nxt;
		} e[M << 1];
		void add_edge(int u, int v, ll w) {
			e[++tot] = (Edge) {v, w, tot ^ 1, head[u]}, head[u] = tot;
			e[++tot] = (Edge) {u, 0, tot ^ 1, head[v]}, head[v] = tot;
		}
		NetworkFlow() {tot = 1;}

		int dis[N];
		queue <int> q;
		bool bfs() {
			while (!q.empty()) q.pop();
			memset (dis, 127 / 3, sizeof dis);
			dis[S] = 0;
			q.push(S);
			while (!q.empty()) {
				int u = q.front(); q.pop();
				for (int i = head[u]; i; i = e[i].nxt) {
					int v = e[i].to;
					if (dis[v] > dis[u] + 1 && e[i].w) {
						dis[v] = dis[u] + 1;
						if (v == T) return 1;
						q.push(v);
					}
				}
			}
			return 0;
		}
		ll dfs (int u, ll flow) {
			if (u == T) return flow;
			ll sum = 0;
			for (int i = head[u]; i; i = e[i].nxt) {
				int v = e[i].to;
				if (dis[v] == dis[u] + 1 && e[i].w) {
					ll f = dfs(v, min(e[i].w, flow - sum));
					if (!f) dis[v] = -1;
					e[i].w -= f;
					e[e[i].op].w += f;
					sum += f;
					if (sum == flow) break;
				}
			}
			return sum;
		}
		ll dinic () { ll ret = 0; for (; bfs(); ret += dfs(S, inf)); return ret; }
	} nf;

费用流

SPFA 倒着搜分层图、最小花费,用到了 SLF 优化,dfs 张昆玮优化。

	struct NetworkFlow {
		const int inf = 707406378;
		int S, T, n;
		int head[N], tot = 1;
		struct Edge {
			int to; ll w, c; int nxt;
		} e[M << 1];
		void add_edge(int u, int v, ll w, ll c) {
			e[++tot] = (Edge) {v, w, c, head[u]}, head[u] = tot;
			e[++tot] = (Edge) {u, 0, -c, head[v]}, head[v] = tot;
		}
		NetworkFlow() {tot = 1;}

		bool vis[N];
		int dis[N];
		deque <int> q;
		bool spfa() {
			while (!q.empty()) q.pop_back();
			for (int i = 1; i <= n; i++) vis[i] = 0, dis[i] = inf;
			dis[T] = 0, vis[T] = 1;
			q.push_back(T);
			while (!q.empty()) {
				int u = q.front(); q.pop_front(); vis[u] = 0;
				for (int i = head[u]; i; i = e[i].nxt) {
					int v = e[i].to;
					if (dis[v] > dis[u] - e[i].c && e[i ^ 1].w) {
						dis[v] = dis[u] - e[i].c;
						if (!vis[v]) {
							vis[v] = 1;
							if (q.size() && dis[v] < dis[q.front()]) q.push_front(v);
							else q.push_back(v);
						}
					}
				}
			}
			return dis[S] < inf;
		}
		ll mcost = 0;
		ll dfs (int u, ll flow) {
			vis[u] = 1;
			if (u == T || !flow) return flow;
			ll sum = 0;
			for (int i = head[u]; i; i = e[i].nxt) {
				int v = e[i].to;
				if (dis[v] == dis[u] - e[i].c && e[i].w && !vis[v]) {
					ll f = dfs(v, min(e[i].w, flow - sum));
					if (!f) continue;
					e[i].w -= f;
					e[i ^ 1].w += f;
					sum += f;
					mcost += f * e[i].c;
					if (sum == flow) break;
				}
			}
			return sum;
		}
		ll mcmf () { 
			ll ret = 0; 
			while (spfa()) {
				vis[T] = 1;
				for (; vis[T]; ret += dfs(S, inf))
					for (int i = 1; i <= n; i++) vis[i] = 0;
			} 
			return ret; 
		}
	} nf;
EOF

评论

暂无评论

发表评论

可以用@mike来提到mike这个用户,mike会被高亮显示。如果你真的想打“@”这个字符,请用“@@”。

博客信息