常用的最大流算法 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(); if(u == e) return true;
 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 }

 

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

// 例题 poj 2516

 

  1 /*
  2  * @Promlem: 
  3  * @Time Limit: ms
  4  * @Memory Limit: k
  5  * @Author: pupil-XJ
  6  * @Date: 2019-11-11 22:37:28
  7  * @LastEditTime: 2019-11-12 11:13:39
  8  */
  9 #include<cstdio>
 10 #include<ctime>
 11 #include<algorithm>
 12 #include<stack>
 13 #include<map>
 14 using namespace std;
 15 const int INF = 0x3f3f3f3f;
 16 typedef pair<int,int> Pair;
 17 const int MAXN = 800+5;
 18 const int MAXE = 102000+5;
 19 
 20 int num;
 21 int head[MAXN];
 22 struct node {
 23     int v, flow, dis;
 24     int next;
 25 } edge[MAXE];
 26 
 27 inline void add(int x, int y, int w, int d) {
 28     edge[num].v = y;
 29     edge[num].flow = w;
 30     edge[num].dis = d;
 31     edge[num].next = head[x];
 32     head[x] = num++;
 33 }
 34 
 35 int n, m, k, sum;
 36 int S, T;
 37 
 38 int maxflow, mincost;
 39 int flow[MAXN], dis[MAXN];
 40 int pre[MAXN], last[MAXN];
 41 bool vis[MAXN];
 42 
 43 bool spfa() {
 44     for(int i = 1; i <= T; ++i) flow[i] = dis[i] = INF, vis[i] = false;
 45     dis[S] = 0;
 46     vis[S] = true;
 47     pre[T] = -1;
 48     stack<int> q;
 49     q.push(S);
 50     while(!q.empty()) {
 51         int u = q.top();
 52         q.pop();
 53         vis[u] = false;
 54         for(int i = head[u]; i != -1; i = edge[i].next) {
 55             int v = edge[i].v;
 56             if(edge[i].flow && dis[v] > dis[u] + edge[i].dis) {
 57                 dis[v] = dis[u] + edge[i].dis;
 58                 pre[v] = u;
 59                 last[v] = i;
 60                 flow[v] = min(flow[u], edge[i].flow);
 61                 if(!vis[v]) {
 62                     vis[v] = true;
 63                     q.push(v);
 64                 }
 65             }
 66         }
 67     }
 68     return  pre[T] != -1;
 69 }
 70 
 71 bool MCMF() {
 72     maxflow = mincost = 0;
 73     while(spfa()) {
 74         maxflow += flow[T];
 75         mincost += flow[T]*dis[T];
 76         int u = T;
 77         while(u != S) {
 78             edge[last[u]].flow -= flow[T];
 79             edge[last[u]^1].flow += flow[T];
 80             u = pre[u];
 81         }
 82     }
 83     return maxflow == sum;
 84 }
 85 
 86 int need[155][155], have[155][155], cost[155][155][155];
 87 
 88 void draw(int k_num) {
 89     S = 1; T = 2+m+n;
 90     num = sum = 0;
 91     for(int i = 1; i <= T; ++i) head[i] = -1;
 92     for(int i = 2; i <= 1+m; ++i) {
 93         add(S, i, have[i-1][k_num], 0);
 94         add(i, S, 0, 0);
 95     }
 96     for(int i = 2; i <= 1+m; ++i) {
 97         for(int j = 2+m; j <= 1+m+n; ++j) {
 98             add(i, j, INF, cost[j-1-m][i-1][k_num]);
 99             add(j, i, 0, -cost[j-1-m][i-1][k_num]);
100         }
101     }
102     for(int i = 2+m; i <= 1+m+n; ++i) {
103         add(i, T, need[i-1-m][k_num], 0);
104         add(T, i, 0, 0);
105         sum += need[i-1-m][k_num];
106     }
107 }
108 
109 int solve() {
110     int ans = 0;
111     for(int i = 1; i <= k; ++i) {
112         draw(i);
113         if(MCMF()) ans += mincost;
114         else return -1;
115     }
116     return ans;
117 }
118 
119 void input() {
120     int x;
121     for(int i = 1; i <= n; ++i) {
122         for(int j = 1; j <= k; ++j) {
123             scanf("%d", &x);
124             need[i][j] = x;
125         }
126     }
127     for(int i = 1; i <= m; ++i) {
128         for(int j = 1; j <= k; ++j) {
129             scanf("%d", &x);
130             have[i][j] = x;
131         }
132     }
133     for(int i = 1; i <= k; ++i) {
134         for(int u = 1; u <= n; ++u) {
135             for(int v = 1; v <= m; ++v) {
136                 scanf("%d", &x);
137                 cost[u][v][i] = x;
138             }
139         }
140     }
141 }
142 
143 int main() {
144     while(1) {
145         scanf("%d%d%d", &n, &m, &k);
146         if(!n) break;
147         input();
148         printf("%d\n", solve());
149     }
150     return 0;
151 }
View Code

 

 

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 }

 

posted @ 2019-11-11 20:05  pupil337  阅读(566)  评论(0编辑  收藏  举报