洛谷 ~ P2604 [ZJOI2010] ~ 網路擴容 (最小費用最大流)
阿新 • • 發佈:2018-12-10
第一問:建邊u->v容量為題中容量,花費為0,跑費用流得到的最大流就是答案。
第二問:建邊u->v容量為INF,花費題中花費,跑費用流得到的費用就是答案。
#include<bits/stdc++.h> using namespace std; const int MAXN = 1e5 + 5; const int INF = 0x3f3f3f3f; struct Edge { int from, to, cap, flow, cost; //起點,終點,容量,流量,花費 Edge(int u, int v, int c, int f, int w):from(u), to(v), cap(c), flow(f), cost(w) {} }; struct MCMF { int n, m; //結點數,邊數(包括反向弧),源點s,匯點t vector<Edge> edges; //邊表。edges[e]和edges[e^1]互為反向弧 vector<int> G[MAXN]; //鄰接表,G[i][j]表示結點i的第j條邊在edges陣列中的序號 bool inq[MAXN]; //是否在佇列中 int d[MAXN]; //Bellman-Ford int p[MAXN]; //上一條弧 int a[MAXN]; //可改進量 void init(int n) { this->n = n; edges.clear(); for (int i = 0; i <= n; i++) G[i].clear(); } void AddEdge(int from, int to, int cap, int cost) { edges.push_back(Edge(from, to, cap, 0, cost)); edges.push_back(Edge(to, from, 0, 0, -cost)); m = edges.size(); G[from].push_back(m - 2); G[to].push_back(m - 1); } bool BellmanFord(int s, int t, int &flow, long long& cost)//SPFA { for (int i = 0; i <= n; i++) d[i] = INF; memset(inq, 0, sizeof(inq)); d[s] = 0; inq[s] = true; p[s] = 0; a[s] = INF; queue<int> Q; Q.push(s); while (!Q.empty()) { int u = Q.front(); Q.pop(); inq[u] = 0; for (int i = 0; i < G[u].size(); i++) { Edge& e = edges[G[u][i]]; if (e.cap > e.flow && d[e.to] > d[u] + e.cost) { d[e.to] = d[u] + e.cost; p[e.to] = G[u][i]; a[e.to] = min(a[u], e.cap - e.flow); if (!inq[e.to]) { Q.push(e.to); inq[e.to] = true; } } } } if (d[t] == INF) return false; flow += a[t]; cost += (long long)d[t] * (long long)a[t]; for (int u = t; u != s; u = edges[p[u]].from) { edges[p[u]].flow += a[t]; edges[p[u]^1].flow -= a[t]; } return true; } int MinCostMaxFlow(int s, int t, long long& cost) { int flow = 0; cost = 0; while (BellmanFord(s, t, flow, cost)); return flow; } }solve; int n, m, k; vector<Edge> IN; int main() { scanf("%d%d%d", &n, &m, &k); for (int i = 0; i < m; i++) { int u, v, c, w; scanf("%d%d%d%d", &u, &v, &c, &w); IN.push_back(Edge(u, v, c, 0, w)); } int s = 1, t = n; solve.init(t); for (int i = 0; i < m; i++) solve.AddEdge(IN[i].from, IN[i].to, IN[i].cap, 0); long long cost1 = 0; int MaxFlow1 = solve.MinCostMaxFlow(s, t, cost1); s = 0; solve.AddEdge(s, 1, k, 0); for (int i = 0; i < m; i++) solve.AddEdge(IN[i].from, IN[i].to, INF, IN[i].cost); long long cost2 = 0; int MaxFlow2 = solve.MinCostMaxFlow(s, t, cost2); printf("%d %lld\n", MaxFlow1, cost2); return 0; } /* 5 8 2 1 2 5 8 2 5 9 9 5 1 6 2 5 1 1 8 1 2 8 7 2 5 4 9 1 2 1 1 1 4 2 1 */