洛谷P3381 最小费用最大流模板

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\n", maxflow, mincost);
91     return 0;
92 }
最小费用最大流模板

 







posted @ 2019-07-25 20:43  缘未到  阅读(130)  评论(0编辑  收藏  举报