HDU ~ 3667 ~ Transportation (費用與流量平方成正比的最小費用最大流)
阿新 • • 發佈:2018-12-09
題意
N個城市,M條邊,你要從1點運送k個貨物到n點。每條邊u,v,a,c表示u->v有一條邊容量為c,從這條邊運送x個物品花費為a*x*x,問最小花費為多少,如果不能運送k個物品到n點輸出-1。
思路
費用與流量平方成正比的最小流。
圖片來自劉汝佳的訓練指南:
#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 add_edge(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) { 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 Mincost_Maxflow(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; int main() { while(~scanf("%d%d%d", &n, &m, &k)) { int s = 0, t = n; solve.init(n); solve.add_edge(s, 1, k, 0); while(m--) { int u, v, a, c; scanf("%d%d%d%d", &u, &v, &a, &c); for (int i = 1; i <= c; i++)//拆邊 solve.add_edge(u, v, 1, a*i*i-a*(i-1)*(i-1)); } long long cost = 0; int Max_Flow = solve.Mincost_Maxflow(s, t, cost); if (Max_Flow != k) printf("-1\n"); else printf("%lld\n", cost); } return 0; } /* 2 1 2 1 2 1 2 2 1 2 1 2 1 1 2 2 2 1 2 1 2 1 2 2 2 */