网络流

最近浅学了一下网络流相关问题,做了一些基础模板题,存一下板子

最大流

最大流使用的均为 ISAP

P3376 【模板】网络最大流

#include <bits/stdc++.h>
#define INF 9223372036854775807
#define int long long
using namespace std;
const int maxn = 1e7 + 10;
int n, m, s, t, cnt = 1;
int head[maxn], vis[maxn];
int dep[maxn], num[maxn], cur[maxn], p[maxn];
struct node{
  int u, v, nxt, cap, flow;
}e[maxn];
inline void add(int u, int v, int w) {
  e[++cnt].u = u; e[cnt].v = v; 
  e[cnt].cap = w; e[cnt].flow = 0;
  e[cnt].nxt = head[u]; head[u] = cnt;
}
inline void bfs() {
  queue<long long> q;
  vis[t] = 1; dep[t] = 0;
  q.push(t);
  while (!q.empty()) {
    int now = q.front(); q.pop();
    for (int i = head[now]; i; i = e[i].nxt) 
    if (vis[e[i].v] == 0 && e[i].cap == 0) {
      vis[e[i].v] = 1;
      dep[e[i].v] = dep[now] + 1;
      q.push(e[i].v);
    }
  }
}
inline int agument() {
  int x = t, ans = INF;
  while (x != s) {
    ans = min(ans, e[p[x]].cap - e[p[x]].flow);
    x = e[p[x]].u;
  }
  x = t;
  while (x != s) {
    e[p[x]].flow += ans;
    e[p[x] ^ 1].flow -= ans;
    x = e[p[x]].u;
  }
  return ans;
}
long long ISAP() {
  long long flow = 0;
  int x = s;
  for (int i = 1; i <= n; i++) num[dep[i]]++;
  for (int i = 1; i <= cnt; i++) cur[i] = head[i];
  while (dep[s] < n) {
    if (x == t) {
      flow += agument();
      x = s;
    }
    int flag = 0;
    for (int i = cur[x]; i; i = e[i].nxt) 
      if (e[i].cap > e[i].flow && dep[x] == dep[e[i].v] + 1) {
	flag = 1;
	p[e[i].v] = i;
	cur[x] = i;
	x = e[i].v;
	break;
      }
    if (flag == 0) {
      if (--num[dep[x]] == 0) break;
      int mn = n - 1;
      for (int i = head[x]; i; i = e[i].nxt) 
        if (e[i].cap > e[i].flow) mn = min(mn, dep[e[i].v]);
      dep[x] = mn + 1;
      num[dep[x]]++;
      cur[x] = head[x];
      if (x != s) x = e[p[x]].u;
    }
  }
  return flow;
}
signed main() {
  cin >> n >> m >> s >> t;
  for (int i = 1; i <= m; i++) {
    int u, v, w;
    cin >> u >> v >> w;
    add(u, v, w); add(v, u, 0);
  }
  bfs();
  long long ans = ISAP();
  cout << ans << endl;
  return 0;
}

P2756 飞行员配对方案问题

#include <iostream>
#include <cstdio>
#include <cmath>
#include <cstring>
#include <algorithm>
#include <queue>
#define INF 0x7fffffff
using namespace std;
const int maxn = 1e6 + 10;
int n, m, s, t, cnt = 1;
int head[maxn], vis[maxn];
int dep[maxn], num[maxn], cur[maxn], p[maxn];
struct node{
  int u, v, nxt, cap, flow;
}e[maxn];
inline void add(int u, int v, int w) {
  e[++cnt].u = u; e[cnt].v = v; 
  e[cnt].cap = w; e[cnt].flow = 0;
  e[cnt].nxt = head[u]; head[u] = cnt;
}
inline void bfs() {
  /*queue<int> q;
  vis[t] = 1; dep[t] = 0;
  q.push(t);
  while (!q.empty()) {
    int now = q.front(); q.pop();
    for (int i = head[now]; i; i = e[i].nxt) 
      if (vis[e[i].v] == 0 && e[i].cap == 0) {
	vis[e[i].v] = 1;
	dep[e[i].v] = dep[now] + 1;
	q.push(e[i].v);
      }
  }*/
  queue<int> q;
  memset(dep, -1, sizeof(dep));
  dep[t] = 0;
  q.push(t);
  while (!q.empty()) {
    int now = q.front(); q.pop();
    for (int i = head[now]; i; i = e[i].nxt) 
      if (dep[e[i].v] == -1) {
        dep[e[i].v] = dep[now] + 1;
	q.push(e[i].v);
      }
  }
}
inline int agument() {
  int x = t, ans = INF;
  while (x != s) {
    ans = min(ans, e[p[x]].cap - e[p[x]].flow);
    x = e[p[x]].u;
  }
  x = t;
  while (x != s) {
    e[p[x]].flow += ans;
    e[p[x] ^ 1].flow -= ans;
    x = e[p[x]].u;
  }
  return ans;
}
int ISAP() {
  int flow = 0, x = s;
  for (int i = 1; i <= n; i++) num[dep[i]]++;
  for (int i = 1; i <= cnt; i++) cur[i] = head[i];
  while (dep[s] < n) {
    if (x == t) {
      flow += agument();
      x = s;
    }
    int flag = 0;
    for (int i = cur[x]; i; i = e[i].nxt) 
      if (e[i].cap > e[i].flow && dep[x] == dep[e[i].v] + 1) {
        flag = 1;
	p[e[i].v] = i;
	cur[x] = i;
	x = e[i].v;
	break;
      }
    if (flag == 0) {
      if (--num[dep[x]] == 0) break;
      int mn = n - 1;
      for (int i = head[x]; i; i = e[i].nxt) 
	if (e[i].cap > e[i].flow) mn = min(mn, dep[e[i].v]);
      dep[x] = mn + 1;
      num[dep[x]]++;
      cur[x] = head[x];
      if (x != s) x = e[p[x]].u;
    }
  }
  return flow;
}
signed main() {
  cin >> m >> n;
  s = n + 1; t = n + 2;
  int u, v;
  for (int i = 1; i <= m; i++) {
    add(s, i, 1); add(i, s, 0);
  }
  for (int i = m + 1; i <= n; i++) {
    add(i, t, 1); add(t, i, 0);
  }
  while (cin >> u >> v) {
    if (u == -1 && v == -1) break;
    add(u, v, 1); add(v, u, 0);
  }
  bfs();
  int ans = ISAP();
  if (ans == 0) {
    cout << "No Solution!" << endl;
    return 0;
  }
  cout << ans << endl;
  for (int i = 2 + n * 2; i <= cnt; i += 2) 
    if (e[i].flow == e[i].cap)  
      cout << e[i].u << " " << e[i].v << endl;
  return 0;
}

P4001 [ICPC-Beijing 2006] 狼抓兔子

#include <iostream>
#include <cstdio>
#include <cmath>
#include <cstring>
#include <algorithm>
#include <queue>
#define INF 0x7fffffff
using namespace std;
const int maxn = 6e6 + 10;
int n, m, s, t, cnt = 1;
int head[maxn], vis[maxn];
int dep[maxn], num[maxn], cur[maxn], p[maxn];
struct node{
  int u, v, nxt, cap, flow;
}e[maxn];
inline void add(int u, int v, int w) {
  e[++cnt].u = u; e[cnt].v = v; 
  e[cnt].cap = w; e[cnt].flow = 0;
  e[cnt].nxt = head[u]; head[u] = cnt;
}
inline void bfs() {
  /*queue<int> q;
  vis[t] = 1; dep[t] = 0;
  q.push(t);
  while (!q.empty()) {
    int now = q.front(); q.pop();
    for (int i = head[now]; i; i = e[i].nxt) 
      if (vis[e[i].v] == 0 && e[i].cap == 0) {
	vis[e[i].v] = 1;
	dep[e[i].v] = dep[now] + 1;
	q.push(e[i].v);
      }
  }*/
  queue<int> q;
  memset(dep, -1, sizeof(dep));
  dep[t] = 0;
  q.push(t);
  while (!q.empty()) {
    int now = q.front(); q.pop();
    for (int i = head[now]; i; i = e[i].nxt) 
      if (dep[e[i].v] == -1) {
        dep[e[i].v] = dep[now] + 1;
	q.push(e[i].v);
      }
  }
}
inline int agument() {
  int x = t, ans = INF;
  while (x != s) {
    ans = min(ans, e[p[x]].cap - e[p[x]].flow);
    x = e[p[x]].u;
  }
  x = t;
  while (x != s) {
    e[p[x]].flow += ans;
    e[p[x] ^ 1].flow -= ans;
    x = e[p[x]].u;
  }
  return ans;
}
int ISAP() {
  int flow = 0, x = s;
  for (int i = 1; i <= n; i++) num[dep[i]]++;
  for (int i = 1; i <= cnt; i++) cur[i] = head[i];
  while (dep[s] < n) {
    if (x == t) {
      flow += agument();
      x = s;
    }
    int flag = 0;
    for (int i = cur[x]; i; i = e[i].nxt) 
      if (e[i].cap > e[i].flow && dep[x] == dep[e[i].v] + 1) {
        flag = 1;
	p[e[i].v] = i;
	cur[x] = i;
	x = e[i].v;
	break;
      }
    if (flag == 0) {
      if (--num[dep[x]] == 0) break;
      int mn = n - 1;
      for (int i = head[x]; i; i = e[i].nxt) 
	if (e[i].cap > e[i].flow) mn = min(mn, dep[e[i].v]);
      dep[x] = mn + 1;
      num[dep[x]]++;
      cur[x] = head[x];
      if (x != s) x = e[p[x]].u;
    }
  }
  return flow;
}
signed main() {
  cin >> n >> m;
  s = 1; t = n * m ;
  for (int i = 1; i <= n; i++)
    for (int j = 1; j < m; j++) {
      int x;
      cin >> x;
      int u = (i - 1) * m + j;
      int v = (i - 1) * m + j + 1;
      add(u, v, x); add(v, u, x);
    }
  for (int i = 1; i < n; i++) 
    for (int j = 1; j <= m; j++) {
      int x;
      cin >> x;
      int u = (i - 1) * m + j;
      int v = i * m + j;
      add(u, v, x); add(v, u, x);
    }
  for (int i = 1; i < n; i++)
    for (int j = 1; j < m; j++) {
      int x;
      cin >> x;
      int u = (i - 1) * m + j;
      int v = i * m + j + 1;
      add(u, v, x); add(v, u, x);
    }
  n = n * m;
  bfs();
  int ans = ISAP();
  cout << ans << endl;
  return 0;
}

费用流

均基于 dinic 算法实现

P3381 【模板】最小费用最大流

普通解法

#include <bits/stdc++.h>
#define INF 0x3f3f3f3f
using namespace std;
const int maxn = 1e7 + 10;
int n, m, s, t, cnt = 1, ret;
int head[maxn], vis[maxn], dis[maxn], cur[maxn];
struct node{
  int v, nxt, cap, flow;
}e[maxn];
inline void add(int u, int v, int w, int c) {
  e[++cnt].v = v;
  e[cnt].flow = w; e[cnt].cap = c;
  e[cnt].nxt = head[u]; head[u] = cnt;
}
inline bool spfa(int s, int t) {
  for (int i = 1; i <= n; i++) cur[i] = head[i];
  queue<int> q;
  for (int i = 1; i <= n; i++) dis[i] = INF;
  dis[s] = 0; vis[s] = 1;
  q.push(s);
  while (!q.empty()) {
    int now = q.front(); q.pop();
    vis[now] = 0;
    for (int i = head[now]; i; i = e[i].nxt) {
      int to = e[i].v;
      if (e[i].flow && dis[to] > dis[now] + e[i].cap) {
	dis[to] = dis[now] + e[i].cap;
	if (vis[to]) continue;
	vis[to] = 1;
	q.push(to);
      }
    }
  }
  return dis[t] != INF;
}
int dfs(int u, int t, int flow) {
  if (u == t) return flow;
  vis[u] = 1;
  int ans = 0;
  for (int i = cur[u]; i && ans < flow; i = e[i].nxt) {
    int v = e[i].v;
    if (!vis[v] && e[i].flow && dis[v] == dis[u] + e[i].cap) {
      int x = dfs(v, t, min(e[i].flow, flow - ans));
      if (x) {
        ret += x * e[i].cap;
        e[i].flow -= x;
        e[i ^ 1].flow += x;
	ans += x;
      }
    }
  }
  vis[u] = 0;
  return ans;
}
int mcmf(int s, int t) {
  int ans = 0;
  while (spfa(s, t)) {
    int x;
    while ((x = dfs(s, t, INF))) ans += x;
  }
  return ans;
}
int main() {
  cin >> n >> m >> s >> t;
  for (int i = 1; i <= m; i++) {
    int u, v, w, c;
    cin >> u >> v >> w >> c;
    add(u, v, w, c); add(v, u, 0, -c);
  }
  int ans = mcmf(s, t);
  cout << ans << " " << ret << endl;
  return 0;
}

Primal-Dual 原始对偶算法

需要开 O2 才能过,还是不要用了 QAQ

#include <bits/stdc++.h>
#define INF 0x7fffffff
using namespace std;
const int maxn = 1e7 + 10;
int n, m, s, t, cnt = 1, maxf, minc;
int head[maxn], vis[maxn], dis[maxn], h[maxn];
struct node{
  int v, nxt, cap, flow;
}e[maxn];
struct noda{
  int v, e;
}p[maxn];
inline void add(int u, int v, int w, int c) {
  e[++cnt].v = v;
  e[cnt].flow = w; e[cnt].cap = c;
  e[cnt].nxt = head[u]; head[u] = cnt;
}
inline void spfa() {
  queue<int> q;
  memset(h, 0x3f, sizeof(h));
  h[s] = 0; vis[s] = 1;
  q.push(s);
  while (!q.empty()) {
    int now = q.front(); q.pop();
    vis[now] = 0;
    for (int i = head[now]; i; i = e[i].nxt) {
      int to = e[i].v;
      if (e[i].flow && h[to] > h[now] + e[i].cap) {
        h[to] = h[now] + e[i].cap;
	if (vis[to]) continue;
	vis[to] = 1;
	q.push(to);
      }
    }
  }
}
inline bool dijkstra() {
  priority_queue<pair<int, int>, vector<pair<int, int> >, greater<pair<int, int> > > q;
  for (int i = 1; i <= n; i++) dis[i] = INF;
  memset(vis, 0, sizeof(vis));
  dis[s] = 0;
  q.push(make_pair(0, s));
  while (!q.empty()) {
    int now = q.top().second; q.pop();
    if (vis[now]) continue;
    vis[now] = 1;
    for (int i = head[now]; i; i = e[i].nxt) {
      int to = e[i].v, nc = e[i].cap + h[now] - h[to];
      if (e[i].flow && dis[to] > dis[now] + nc) {
        dis[to] = dis[now] + nc;
	p[to].v = now;
	p[to].e = i;
	if (!vis[to]) q.push(make_pair(dis[to], to));
      }
    }
  }
  return dis[t] != INF;
}
int main() {
  cin >> n >> m >> s >> t;
  for (int i = 1; i <= m; i++) {
    int u, v, w, c;
    cin >> u >> v >> w >> c;
    add(u, v, w, c); add(v, u, 0, -c);
  }
  spfa();
  while (dijkstra()) {
    int minf = INF;
    for (int i = 1; i <= n; i++) h[i] += dis[i];
    for (int i = t; i != s; i = p[i].v) minf = min(minf, e[p[i].e].flow);
    for (int i = t; i != s; i = p[i].v) {
      e[p[i].e].flow -= minf;
      e[p[i].e ^ 1].flow += minf;
    }
    maxf += minf;
    minc += minf * h[t];
  }
  cout << maxf << " " << minc << endl;
  return 0;
}

P4016 负载平衡问题

#include <bits/stdc++.h>
#define INF 0x3f3f3f3f
using namespace std;
const int maxn = 1e7 + 10;
int n, m, cnt = 1;
int head[maxn], vis[maxn], dis[maxn], cur[maxn];
long long sum, ret, a[maxn];
struct node{
  int v, nxt, cap;
  long long flow;
}e[maxn];
inline void add(int u, int v, long long w, int c) {
  e[++cnt].v = v;
  e[cnt].flow = w; e[cnt].cap = c;
  e[cnt].nxt = head[u]; head[u] = cnt;
}
inline bool spfa(int s, int t) {
  //for (int i = 0; i <= t; i++) cur[i] = head[i], dis[i] = INF;
  memset(dis, 0x3f, sizeof(dis));
  memcpy(cur, head, sizeof(head));
  queue<int> q;
  dis[s] = 0; vis[s] = 1;
  q.push(s);
  while (!q.empty()) {
    int now = q.front(); q.pop();
    vis[now] = 0;
    for (int i = head[now]; i; i = e[i].nxt) {
      int to = e[i].v;
      if (e[i].flow && dis[to] > dis[now] + e[i].cap) {
        dis[to] = dis[now] + e[i].cap;
	if (vis[to]) continue;
	vis[to] = 1;
	q.push(to);
      }
    }
  }
  return dis[t] != INF;
}
long long dfs(int u, int t, long long flow) {
  if (u == t) return flow;
  vis[u] = 1;
  long long ans = 0;
  for (int i = cur[u]; i && ans < flow; i = e[i].nxt) {
    int v = e[i].v;
    if (!vis[v] && e[i].flow && dis[v] == dis[u] + e[i].cap) {
      int x = dfs(v, t, min(e[i].flow, flow - ans));
      if (x) {
        ret += x * e[i].cap;
  	e[i].flow -= x;
  	e[i ^ 1].flow += x;
  	ans += x;
      }
    }
  }
  vis[u] = 0;
  return ans;
}
void mcmf(int s, int t) {
  int ans = 0;
  while (spfa(s, t)) {
    int x;
    while ((x = dfs(s, t, INF))) ans += x;
    //cout << "dfs: " << x << endl;
  }
}
signed main() {
  cin >> n;
  int s, t;
  s = 0; t = n + 1;
  for (int i = 1; i <= n; i++) {
    cin >> a[i];
    sum += a[i];
  }
  sum /= n;
  for (int i = 1; i <= n; i++) {
    if (a[i] > sum) {
      add(s, i, a[i] - sum, 0);
      add(i, s, 0, 0);
    } else if (a[i] < sum) {
      add(i, t, sum - a[i], 0);
      add(t, i, 0, 0);
    }
    if (i == 1) {
      add(1, n, INF, 1);
      add(n, 1, 0, -1);
      add(n, 1, INF, 1);
      add(1, n, 0, -1);
    } else {
      add(i - 1, i, INF, 1);
      add(i, i - 1, 0, -1);
      add(i, i - 1, INF, 1);
      add(i - 1, i, 0, -1);
    }
  }
  mcmf(s, t);
  cout << ret << endl;
  return 0;
}

最小割

P1345 [USACO5.4]奶牛的电信Telecowmunication

#include <bits/stdc++.h>
#define INF 0x3f3f3f3f
using namespace std;
const int maxn = 1e7 + 10;
int n, m, s, t, cnt = 1;
int head[maxn], dep[maxn], cur[maxn];
struct node{
  int v, flow, nxt;
}e[maxn];
inline void add(int u, int v, int w) {
  e[++cnt].v = v; e[cnt].flow = w;
  e[cnt].nxt = head[u]; head[u] = cnt;
}
int bfs(int s, int t) {
  memset(dep, 0, sizeof(dep));
  memcpy(cur, head, sizeof(head));
  queue<int> q;
  dep[s] = 1;
  q.push(s);
  while (!q.empty()) {
    int u = q.front(); q.pop();
    for (int i = head[u]; i; i = e[i].nxt) {
      int v = e[i].v;
      if (e[i].flow && !dep[v]) {
	q.push(v);  
        dep[v] = dep[u] + 1;
      }
    }
  }
  return dep[t];
}
int dfs(int u, int t, int flow) {
  if (u == t) return flow;
  int ans = 0;
  for (int i = head[u]; i && ans < flow; i = e[i].nxt) {
    int v = e[i].v;
    if (e[i].flow && dep[v] == dep[u] + 1) {
      int x = dfs(v, t, min(e[i].flow, flow - ans));
      if (x) {
	e[i].flow -= x;
	e[i ^ 1].flow += x;
	ans += x;
      }	
    }
  }
  if (ans < flow) dep[u] = -1;
  return ans;
}
int dinic(int s, int t) {
  int ans = 0;
  while (bfs(s, t)) {
    int x;
    while ((x = dfs(s, t, INF))) ans += x;
  }
  return ans;
}
int main() {
  cin >> n >> m >> s >> t;
  s += n;
  for (int i = 1; i <= n; i++) {
    add(i, i + n, 1); add(i + n, i, 0);
  }
  for (int i = 1; i <= m; i++) {
    int u, v;
    cin >> u >> v;
    add(u + n, v, INF);
    add(v, u + n, 0);
    add(v + n, u, INF);
    add(u, v + n, 0);
  }
  int ans = dinic(s, t);
  cout << ans << endl;
  return 0;
}

P2057 [SHOI2007]善意的投票 / [JLOI2010]冠军调查

#include <bits/stdc++.h>
#define INF 0x3f3f3f3f
using namespace std;
const int maxn = 1e7 + 10;
int n, m, s, t, cnt = 1;
int head[maxn], dep[maxn], cur[maxn];
struct node{
  int v, flow, nxt;
}e[maxn];
inline void add(int u, int v, int w) {
  e[++cnt].v = v; e[cnt].flow = w;
  e[cnt].nxt = head[u]; head[u] = cnt;
}
int bfs(int s, int t) {
  memset(dep, 0, sizeof(dep));
  memcpy(cur, head, sizeof(head));
  queue<int> q;
  dep[s] = 1;
  q.push(s);
  while (!q.empty()) {
    int u = q.front(); q.pop();
    for (int i = head[u]; i; i = e[i].nxt) {
      int v = e[i].v;
      if (e[i].flow && !dep[v]) {
	q.push(v); 
        dep[v] = dep[u] + 1;
      }
    }
  }
  return dep[t];
}
int dfs(int u, int t, int flow) {
  if (u == t) return flow;
  int ans = 0;
  for (int i = head[u]; i && ans < flow; i = e[i].nxt) {
    int v = e[i].v;
    if (e[i].flow && dep[v] == dep[u] + 1) {
      int x = dfs(v, t, min(e[i].flow, flow - ans));
      if (x) {
        e[i].flow -= x;
	e[i ^ 1].flow += x;
	ans += x;
      }	
    }
  }
  if (ans < flow) dep[u] = -1;
  return ans;
}
int dinic(int s, int t) {
  int ans = 0;
  while (bfs(s, t)) {
    int x;
    while ((x = dfs(s, t, INF))) ans += x;
  }
  return ans;
}
int main() {
  cin >> n >> m;
  s = 0; t = n + 1;
  for (int i = 1; i <= n; i++) {
    int x;
    cin >> x;
    if (x == 1) add(s, i, 1), add(i, s, 0);
    else add(i, t, 1), add(t, i, 0);
  }
  for (int i = 1; i <= m; i++) {
    int u, v;
    cin >> u >> v;
    add(u, v, 1); add(v, u, 0);
    add(v, u, 1); add(u, v, 0);
  }
  int ans = dinic(s, t);
  cout << ans << endl;
  return 0;
}
posted @ 2022-04-09 18:05  Moominn  阅读(51)  评论(0编辑  收藏  举报