https://www.luogu.org/problem/P3381
题目描述
如题,给出一个网络图,以及其源点和汇点,每条边已知其最大流量和单位流量费用,求出其网络最大流和在最大流情况下的最小费用。
输入格式
第一行包含四个正整数N、M、S、T,分别表示点的个数、有向边的个数、源点序号、汇点序号。
接下来M行每行包含四个正整数ui、vi、wi、fi,表示第i条有向边从ui出发,到达vi,边权为wi(即该边最大流量为wi),单位流量的费用为fi。
输出格式
一行,包含两个整数,依次为最大流量和在最大流量情况下的最小费用。
输入
4 5 4 3 4 2 30 2 4 3 20 3 2 3 20 1 2 1 30 9 1 3 40 5
输出
最小费用最大流模板
50 280
1 #include<stdio.h> 2 #include<string.h> 3 #include<queue> 4 #define mem(a, b) memset(a, b, sizeof(a)) 5 using namespace std; 6 const int MAXN = 1e5 + 10; 7 const int inf = 0x3f3f3f3f; 8 9 int n, m, st, ed;//点数 边数 源点 汇点 10 int vis[MAXN], dis[MAXN], flow[MAXN];//源点到i点的花费和流量 11 int pre[MAXN];//每个点的前驱 12 int last[MAXN]; //每个点连的前一条边 13 int mincost, maxflow; 14 queue<int> Q; 15 16 struct Edge 17 { 18 int to, next, flow, dis;//费用作为 dis 来跑最短路 19 }edge[MAXN]; 20 int head[MAXN], cnt; 21 22 void add(int a, int b, int c, int d) //要用到 ^ 操作 所以边从 0 开始 23 { 24 edge[++ cnt].to = b; 25 edge[cnt].next = head[a]; 26 edge[cnt].flow = c; 27 edge[cnt].dis = d; 28 head[a] = cnt; 29 } 30 31 bool spfa(int st, int ed) 32 { 33 mem(dis, inf), mem(flow, inf), mem(vis, 0);//找到最大流以及最短路(最少费用) 34 Q.push(st); 35 vis[st] = 1; 36 dis[st] = 0; 37 pre[ed] = -1; 38 while(!Q.empty()) 39 { 40 int now = Q.front(); 41 Q.pop(); 42 vis[now] = 0; 43 for(int i = head[now]; i != -1; i = edge[i].next) 44 { 45 if(edge[i].flow > 0 && dis[edge[i].to] > dis[now] + edge[i].dis) 46 { 47 dis[edge[i].to] = dis[now] + edge[i].dis; 48 pre[edge[i].to] = now;//记录更新后的新前驱 49 last[edge[i].to] = i;//记录更新后的新的前一条边 为了回溯来更新边的流量 50 flow[edge[i].to] = min(flow[now], edge[i].flow);//找出最大流 51 if(!vis[edge[i].to]) 52 { 53 vis[edge[i].to] = 1; 54 Q.push(edge[i].to); 55 } 56 } 57 } 58 } 59 return pre[ed] != -1; 60 } 61 62 void min_cost_max_flow() 63 { 64 while(spfa(st, ed)) 65 { 66 int now = ed; 67 maxflow += flow[ed]; 68 mincost += flow[ed] * dis[ed]; 69 while(now != st)//从汇点回溯更新边剩下的流量 70 { 71 edge[last[now]].flow -= flow[ed]; 72 edge[last[now] ^ 1].flow += flow[ed]; 73 now = pre[now]; 74 } 75 } 76 } 77 78 int main() 79 { 80 mem(head, -1), cnt = -1; 81 scanf("%d%d%d%d", &n, &m, &st, &ed); 82 for(int i = 1; i <= m; i ++) 83 { 84 int a, b, c, d; 85 scanf("%d%d%d%d", &a, &b, &c, &d); //有向边起点 终点 容量 单位费用 86 add(a, b, c, d); 87 add(b, a, 0, -d);//反向边流量为 0 ,花费为 负的 88 } 89 min_cost_max_flow(); 90 printf("%d %d ", maxflow, mincost); 91 return 0; 92 }