常用的最大流算法 Dinic 和 最小费用最大流SPFA写法

// Dinic 是EK的优化 (都是FF思想)

//附带EK算法O(V*E2):

 1 #include<cstdio>
 2 #include<algorithm>
 3 #include<queue>
 4 #define INF 0x3f3f3f3f
 5 using namespace std;
 6 
 7 inline int read() {
 8     char c=getchar();int x=0,f=1;
 9     while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
10     while(c>='0'&&c<='9'){x=x*10+c-'0';c=getchar();}
11     return x*f;
12 }
13 
14 const int MAXN = 10000+5;
15 const int MAXE = 100000*2+5;
16 
17 int num;
18 int head[MAXN];
19 struct node {
20     int u, v, flow;
21     int next;
22 } edge[MAXE];
23 
24 inline void add(int x, int y, int w) {
25     edge[num].u = x;
26     edge[num].v = y;
27     edge[num].flow = w;
28     edge[num].next = head[x];
29     head[x] = num++;
30 }
31 
32 int n, m, s, e;
33 int path[MAXN], A[MAXN];
34 
35 int EK() {
36     int ans = 0;
37     while(1) {
38         for(int i = 1; i <= n; ++i) A[i] = 0;
39         queue<int> q;
40         q.push(s);
41         A[s] = INF;
42         while(!q.empty()) {
43             int u = q.front();
44             q.pop();
45             for(int i = head[u]; i != -1; i = edge[i].next) {
46                 int v = edge[i].v;
47                 if(!A[v] && edge[i].flow) {
48                     path[v] = i;
49                     A[v] = min(A[u], edge[i].flow);
50                     q.push(v);
51                 }
52             }
53             if(A[e]) break;
54         }
55         if(!A[e]) break;
56         for(int i = e; i != s; i = edge[path[i]].u) {
57             edge[path[i]].flow -= A[e];
58             edge[path[i]^1].flow += A[e];
59         }
60         ans += A[e];
61     }
62     return ans;
63 }
64 
65 int main() {
66     n = read(); m = read(); s = read(); e = read();
67     num = 0;
68     for(int i = 1; i <= n; ++i) head[i] = -1;
69     for(int i = 0; i != m; ++i) {
70         int x = read(), y = read(), w = read();
71         add(x, y, w);
72         add(y, x, 0);
73     }
74     printf("%d\n", EK());
75     return 0;
76 }
View Code

Dinic 参考博客 点我.

Dinic 的三种优化: 当前弧优化、多路增广、炸点 。上面的博客讲的很清楚

代码:

  1 /*
  2  * @Promlem: 
  3  * @Time Limit: ms
  4  * @Memory Limit: k
  5  * @Author: pupil-XJ
  6  * @Date: 2019-11-10 19:34:37
  7  * @LastEditTime: 2019-11-10 20:56:40
  8  */
  9 #include<cstdio>
 10 #include<algorithm>
 11 #include<queue>
 12 #define INF 0x3f3f3f3f
 13 using namespace std;
 14 
 15 inline int read() {
 16     char c=getchar();int x=0,f=1;
 17     while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
 18     while(c>='0'&&c<='9'){x=x*10+c-'0';c=getchar();}
 19     return x*f;
 20 }
 21 
 22 const int MAXN = 200+5;
 23 const int MAXE = 200*2+5;
 24 
 25 int num;
 26 int head[MAXN];
 27 struct node {
 28     int v, flow;
 29     int next;
 30 } edge[MAXN];
 31 
 32 inline void add(int x, int y, int w) {
 33     edge[num].v = y;
 34     edge[num].flow = w;
 35     edge[num].next = head[x];
 36     head[x] = num++;
 37 }
 38 
 39 int n, m, s, e;
 40 int cur[MAXN], dis[MAXN];
 41 
 42 bool bfs() {
 43     for(int i = 1; i <= n; ++i) dis[i] = 0;
 44     dis[s] = 1;
 45     queue<int> q;
 46     q.push(s);
 47     while(!q.empty()) {
 48         int u = q.front();
 49         q.pop();
 50         for(int i = head[u]; i != -1; i = edge[i].next) {
 51             int v = edge[i].v;
 52             if(!dis[v] && edge[i].flow) {
 53                 dis[v] = dis[u] + 1;
 54                 q.push(v);
 55             }
 56         }
 57     }
 58     return dis[e] != 0;
 59 }
 60 
 61 int dfs(int u, int f) { //当前节点,到目前为止可增加流量。返回可增加流量
 62     if(u == e || (!f)) return f; // 到达汇点 || 已无残量
 63     int flow = 0;
 64     for(int& i = cur[u]; i != -1; i = edge[i].next) {// '&'目的 -> 当前弧优化
 65         int v = edge[i].v;
 66         if(dis[v] == dis[u] + 1) {
 67             int di = dfs(v, min(f, edge[i].flow));
 68             if(di > 0) {
 69                 flow += di;//这里不急着return,而是记录一下这条链上能增广的流量,再接着找下一条链
 70                 f -= di;//把从u开始能增广的容量相应减去
 71                 edge[i].flow -= di;
 72                 edge[i^1].flow += di;
 73                 if(!f) break;// 没容量了
 74             }
 75         }
 76     }
 77     if(!flow) dis[u] = -1;//这个点甚至没有增广出一点流量,炸掉它
 78     return flow;
 79 }
 80 
 81 int Dinic() {
 82     int ans = 0;
 83     while(bfs()) {
 84         for(int i = 1; i <= n; ++i) cur[i] = head[i];
 85         ans += dfs(s, INF);
 86     }
 87     return ans;
 88 }
 89 
 90 int main() {
 91     n = read(); m = read(); s = read(); e = read();
 92     num = 0;
 93     for(int i = 1; i <= n; ++i) head[i] = -1;
 94     for(int i = 0; i != m; ++i) {
 95         int x = read(), y = read(), w = read();
 96         add(x, y, w);
 97         add(y, x, 0);
 98     }
 99     printf("%d\n", Dinic());
100     return 0;
101 }

 // 费用流 定义: 百度百科

SPFA写法--在每次找增广路的时候选择找一条到汇点费用之和最小的链 然后 ans += 当前找到的最短路*每次的增广量

(dijkstra不会。。。)

  1 /*
  2  * @Promlem: 
  3  * @Time Limit: ms
  4  * @Memory Limit: k
  5  * @Author: pupil-XJ
  6  * @Date: 2019-11-11 19:02:37
  7  * @LastEditTime: 2019-11-11 19:20:27
  8  */
  9 
 10 #include<cstdio>
 11 #include<algorithm>
 12 #include<queue>
 13 #define INF 0x3f3f3f3f
 14 using namespace std;
 15 
 16 inline int read() {
 17     char c=getchar();int x=0,f=1;
 18     while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
 19     while(c>='0'&&c<='9'){x=x*10+c-'0';c=getchar();}
 20     return x*f;
 21 }
 22 
 23 const int MAXN = 200+5;
 24 const int MAXE = 200*2+5;
 25 
 26 int num;
 27 int head[MAXN];
 28 struct node {
 29     int v, flow, dis;
 30     int next;
 31 } edge[MAXN];
 32 
 33 inline void add(int x, int y, int w, int dis) {
 34     edge[num].v = y;
 35     edge[num].flow = w;
 36     edge[num].dis = dis;
 37     edge[num].next = head[x];
 38     head[x] = num++;
 39 }
 40 
 41 int n, m, s, e;
 42 int maxflow, mincost;
 43 int flow[MAXN], dis[MAXN];
 44 int pre[MAXN], last[MAXN];
 45 bool vis[MAXN];
 46 
 47 bool spfa() {
 48     for(int i = 1; i <= n; ++i) flow[i] = dis[i] = INF, vis[i] = false;
 49     vis[s] = true;
 50     dis[s] = 0; pre[e] = -1;
 51     queue<int> q;
 52     q.push(s);
 53     while(!q.empty()) {
 54         int u = q.front();
 55         q.pop();
 56         vis[u] = false;
 57         for(int i = head[u]; i != -1; i = edge[i].next) {
 58             int v = edge[i].v;
 59             if(edge[i].flow && dis[v] > dis[u] + edge[i].dis) {
 60                 dis[v] = dis[u] + edge[i].dis;
 61                 pre[v] = u;
 62                 last[v] = i;
 63                 flow[v] = min(flow[u], edge[i].flow);
 64                 if(!vis[v]) {
 65                     vis[v] = true;
 66                     q.push(v);
 67                 }
 68             }
 69         }
 70     }
 71     return pre[e] != -1;
 72 }
 73 
 74 void MCMF() {
 75     maxflow = mincost = 0;
 76     while(spfa()) {
 77         int u = e;
 78         maxflow += flow[u];
 79         mincost += flow[u]*dis[u];
 80         while(u != s) {
 81             edge[last[u]].flow -= flow[e];
 82             edge[last[u]^1].flow += flow[e];
 83             u = pre[u];
 84         }
 85     }
 86 }
 87 
 88 int main() {
 89     n = read(); m = read(); s = read(); e = read();
 90     num = 0;
 91     for(int i = 1; i <= n; ++i) head[i] = -1;
 92     for(int i = 0; i != m; ++i) {
 93         int x = read(), y = read(), w = read(), f = read();
 94         add(x, y, w, f);
 95         add(y, x, 0,-f);
 96     }
 97     MCMF();
 98     printf("%d %d\n", maxflow, mincost);
 99     return 0;
100 }

猜你喜欢

转载自www.cnblogs.com/pupil-xj/p/11831860.html