题目大意是从1节点到n节点运送物品,给定m条边的起点和终点,容量和费用,求把这些东西送到终点的最小费用是多少,如果不能全部送达则输出-1
思路
网络流
这题可以用SPFA的最小费用最大流模板来处理,唯一的难点就在于见图,从一个顶点u 到 v 的费用为 当前的流量值
的平方 * ai ai为开始给定的每个道路的费用。由于我们要算的是流量的平方,可以构建一个等差数列1,3,5....对于
每一条边我们可以拆分成容量为1的边,这样见图就可以直接算出费用。同时见图开始可以加一条虚边,保证最大流
量是K。
#include <cstdio> #include <cstring> #include <algorithm> #include <queue> using namespace std; const int maxn = 50000 + 10; const int maxm = 50000 + 10; const int INF = 0x3f3f3f3f; struct Edge{ Edge() {}; Edge(int a, int b, int c, int d) {v = a; f = b; w = c; nxt = d;} int v, f, w, nxt; }e[maxm]; int n, K; int g[maxn]; int nume; int src, sink; void addedge(int u, int v, int c, int w){ e[++nume] = Edge(v, c, w, g[u]); g[u] = nume; e[++nume] = Edge(u, 0, -w, g[v]); g[v] = nume; } queue<int> q; bool inque[maxn]; int dis[maxn]; int Prev[maxn], pree[maxm]; bool findPath(){ while(!q.empty()) q.pop(); q.push(src); memset(dis, 63, sizeof(dis)); dis[src] = 0; inque[src] = true; while(!q.empty()){ int u = q.front(); q.pop(); for(int i = g[u]; i; i = e[i].nxt){ if(e[i].f > 0 && dis[u] + e[i].w < dis[e[i].v]){ dis[e[i].v] = dis[u] + e[i].w; Prev[e[i].v] = u; pree[e[i].v] = i; if(!inque[e[i].v]){ inque[e[i].v] = true; q.push(e[i].v); } } } inque[u] = false; } if(dis[sink] < INF) return true; return false; } int augment(int & flow){ int u = sink; int delta = INF; while(u != src){ if(e[pree[u]].f < delta) delta = e[pree[u]].f; u = Prev[u]; } u = sink; while(u != src){ e[pree[u]].f -= delta; e[pree[u] ^ 1].f += delta; u = Prev[u]; } flow += delta; return dis[sink] * delta; } int mincostflow(){ int cur = 0, ans = 0; int _flow = 0; while(findPath()){ cur += augment(_flow); if(cur < ans) ans = cur; } if(_flow < K) return -1; return cur; } int main() { int m; while(scanf("%d %d%d", &n, &m, &K) == 3){ memset(g, 0, sizeof(g)); nume = 1; int u, v, a, c; while(m --){ scanf("%d%d%d%d", &u, &v, &a, &c); int t = 1; for(int i = 1; i <= c; ++i){ addedge(u, v, 1, a * t); t += 2; } } addedge(0, 1, K, 0); src = 0; sink = n; printf("%d\n", mincostflow()); } return 0; }