第一次做网络流, 纪念一小下吧
代码写得比较蹉, 很多能优化的地方都只能放弃, 只是体验一下这个过程, 优化了反而复杂了
EK算法
邻接矩阵表示:
#include <cstring>
#include <cstdio>
#include <algorithm>
#include <queue>
#pragma warning(disable:4996)
using namespace std;
#define CLR(arr, v) memset(arr, v, sizeof(arr))
const int M = 20;
int map[M][M];
int f[M][M];
int vexNum, edgeNum;
int s, t;
int path[20], flow[20];
bool vis[20];
bool bfs()
{
queue<int> Q;
CLR(flow, 0);
CLR(vis, false);
vis[s] = true;
Q.push(s);
flow[s] = 1e9;
while(!Q.empty())
{
int top = Q.front();
for(int i = 1; i <= vexNum; i++)
{
if(top != i && !vis[i] && map[top][i] > f[top][i])
{
path[i] = top;
vis[i] = true;
flow[i] = min(flow[top], map[top][i] - f[top][i]); //注意是flow[top]
if(i == t)
return true;
Q.push(i);
}
}
Q.pop();
}
return false;
}
int ek()
{
int maxFlow = 0, j;
CLR(f, 0);
while(bfs())
{
for(int j = t, i = path[j]; j != s;)
{
f[i][j] += flow[t];
f[j][i] -= flow[t]; //更新反向边
j = i;
i = path[i];
}
maxFlow += flow[t];
}
return maxFlow;
}
int main()
{
int ncase, tmp = 1, u, v, w;
scanf("%d", &ncase);
while(ncase--)
{
CLR(map, 0);
scanf("%d %d", &vexNum, &edgeNum);
for(int i = 0; i < edgeNum; i++)
{
scanf("%d %d %d", &u, &v, &w);
map[u][v] += w;
}
s = 1, t = vexNum;
int ans = ek();
printf("Case %d: %d\n", tmp++, ans);
}
return 0;
}
#include <queue>
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
#define CLR(a, val) memset(a, val, sizeof(a))
#pragma warning(disable:4996)
using namespace std;
const int MaxV = 100;
const int MaxE = 2005; //必须注意这里的2倍
const int INF = 1e9;
template<int MaxV, int MaxE>
struct Graph
{
struct Vertes
{
int head;
}V[MaxV];
struct Edge
{
int arc, c, f, next;
Edge(int arc, int c, int f, int next):arc(arc), c(c), f(f), next(next){}
Edge(){}
}E[MaxE];
int top;
void init()
{
top = 0;
CLR(V, -1);
}
void addEdge(int u, int v, int w)
{
E[top] = Edge(v, w, 0, V[u].head);
V[u].head = top++;
E[top] = Edge(u, 0, 0, V[v].head);
V[v].head = top++;
}
};
int vexNum, edgeNum;
int s, t;
Graph<MaxV, MaxE> g;
int path[MaxE];
int flow[MaxE];
bool bfs(int s, int t)
{
CLR(flow, 0);
queue<int> Q;
Q.push(s);
flow[s] = INF;
while(!Q.empty())
{
int u = Q.front();
for(int i = g.V[u].head; i != -1; i = g.E[i].next)
{
int v = g.E[i].arc;
if(!flow[v] && g.E[i].c - g.E[i].f > 0)
{
path[v] = i;
flow[v] = min(flow[u], g.E[i].c - g.E[i].f);
if(v == t)
return true;
Q.push(v);
}
}
Q.pop();
}
return false;
}
int ek(int s, int t)
{
int i, maxFlow = 0;
while(bfs(s, t))
{
for(int v = t; v != s; v = g.E[i ^ 1].arc)
{
i = path[v];
g.E[i].f += flow[t];
g.E[i ^ 1].f -= flow[t];
}
maxFlow += flow[t];
}
return maxFlow;
}
void debug()
{
for(int i = 1; i <= vexNum; i++)
{
cout << i << ":";
for(int j = g.V[i].head; j != -1; j = g.E[j].next)
{
cout << g.E[j].arc << " ";
}
cout << endl;
}
}
int main()
{
//freopen("data_in.txt", "r", stdin);
int ncase, tmp = 1;
scanf("%d", &ncase);
while(ncase--){
g.init();
int u, v, w;
scanf("%d %d", &vexNum, &edgeNum);
for(int i = 0; i < edgeNum; i++)
{
scanf("%d %d %d", &u, &v, &w);
g.addEdge(u, v, w);
}
//cin >> s >> t;
//debug();
//cout << "Case " << tmp++ << ": " << ek(1, vexNum) << endl;
printf("Case %d: %d\n", tmp++, ek(1, vexNum));
}
return 0;
}
Dinic 算法
#include <queue>
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
#define CLR(a, val) memset(a, val, sizeof(a))
#pragma warning(disable:4996)
using namespace std;
const int MaxV = 100;
const int MaxE = 2005 << 1;
const int INF = 1e9;
template<int MaxV, int MaxE>
struct Graph
{
struct Vertes
{
int head;
}V[MaxV];
struct Edge
{
int arc, c, f, next;
Edge(int arc, int c, int f, int next):arc(arc), c(c), f(f), next(next){}
Edge(){}
}E[MaxE];
int top;
void init()
{
top = 0;
CLR(V, -1);
}
void addEdge(int u, int v, int w)
{
E[top] = Edge(v, w, 0, V[u].head);
V[u].head = top++;
E[top] = Edge(u, 0, 0, V[v].head);
V[v].head = top++;
}
};
int vexNum, edgeNum;
int s, t;
Graph<MaxV, MaxE> g;
int level[MaxV];
int path[MaxV];
bool bfs()
{
queue<int> Q;
CLR(level, -1);
level[s] = 0;
Q.push(s);
while(!Q.empty())
{
int u = Q.front();
for(int i = g.V[u].head; i != -1; i = g.E[i].next)
{
int j = g.E[i].arc;
if(level[j] == -1 && g.E[i].c)
{
level[j] = level[u] + 1;
Q.push(j);
}
}
Q.pop();
}
return level[t] != -1;
}
int dfs(int v, int c)
{
if(v == t)
return c;
int sum = c;
for(int i = g.V[v].head; i != -1; i = g.E[i].next)
{
int j = g.E[i].arc;
if(g.E[i].c > 0 && level[j] == level[v] + 1)
{
int a = dfs(j, min(c, g.E[i].c));
g.E[i].c -= a;
g.E[i ^ 1].c += a;
c -= a;
}
}
return sum - c;
}
int dinic()
{
int ans =0;
while(bfs())
{
ans += dfs(s, INF);
}
return ans;
}
int main()
{
//freopen("data_in.txt", "r", stdin);
int ncase, tmp = 1;
scanf("%d", &ncase);
while(ncase--){
g.init();
int u, v, w;
scanf("%d %d", &vexNum, &edgeNum);
for(int i = 0; i < edgeNum; i++)
{
scanf("%d %d %d", &u, &v, &w);
g.addEdge(u, v, w);
}
s = 1, t = vexNum;
printf("Case %d: %d\n", tmp++, dinic());
}
return 0;
}
dinic 参考代码:http://blog.youkuaiyun.com/birdforever/article/details/5874780
SAP 算法
邻接矩阵实现:
/*
测试用例:
6 5
1 2 2
1 3 5
2 4 1
3 4 6
3 5 1
4 5 5
*/
#include<stdio.h>
#include<string.h>
#include <iostream>
#include <iomanip>
using namespace std;
#pragma warning(disable:4996)
#define CLR(arr, v) memset(arr, v, sizeof(arr))
#define print(a) cout << #a << ": " << a << endl;
#define INF 1<<29;
const int M = 100;
struct sap
{
const int m;
const int s, t;
int cf[M][M];
int flow;
int h[M];
int vh[M];
int cf_path;
bool flag;
sap(int m, int s, int t):m(m), s(s), t(t)
{
CLR(cf, 0);
CLR(h, 0);
CLR(vh, 0);
flow = 0;
flag = false;
}
void find_path(int cur)
{
if(t == cur)
{
flow += cf_path;
flag = true;
return;
}
int tmp_cf_path = cf_path;
int minH = m - 1;
int i;
for(i = 1; i <= m; i++)
{
if(cf[cur][i])
{
if(h[i] == h[cur] - 1)
{
cf_path = min(cf_path, cf[cur][i]);
find_path(i);
if(h[1] >= m)
return;
if(flag)
break;
if(!flag)
cf_path = tmp_cf_path;
}
minH = min(minH, h[i]);
}
}
if(flag)
{
cf[cur][i] -= cf_path;
cf[i][cur] += cf_path;
}
else
{
vh[h[cur]]--;
if(vh[h[cur]] == 0)
h[1] = m;
h[cur] = minH + 1;
vh[h[cur]] += 1;
}
}
int solve()
{
vh[0] = m;
flow = 0;
while(h[1] < m)
{
flag = false;
cf_path = INF;
find_path(s);
}
return flow;
}
void addEdge(int x,int y,int c){
cf[x][y]+=c;
}
};
int main()
{
int n; //有向边数
int m; //顶点数
int ncase, tmp = 1;
scanf("%d", &ncase);
while(ncase--)
{
scanf("%d %d", &m, &n);
sap nt= sap(m, 1, m);
for(int i=1;i<=n;i++)
{
int x,y,c;
scanf("%d %d %d",&x,&y,&c);
nt.addEdge(x,y,c);
}
printf("Case %d: %d\n",tmp++, nt.solve());
}
return 0;
}
sap邻接矩阵参考代码:http://chuanwang66.iteye.com/blog/1450715
邻接表实现:
//SPA
#include <cstring>
#include <cstdio>
#include <queue>
#include <algorithm>
#define CLR(arr, val) memset(arr, val, sizeof(arr))
#pragma warning(disable:4996)
using namespace std;
const int MaxV = 20;
const int MaxE = 1000 << 1;
const int INF = 1e9;
struct Graph
{
struct Vertex
{
int head;
}V[MaxV];
struct Edge
{
int v, c, f, next;
Edge(){}
Edge(int v,int c, int f, int next):v(v), c(c), f(f), next(next){}
}E[MaxE];
void init()
{
top = 0;
CLR(V, -1);
}
void addEdge(int u, int v,int w)
{
E[top] = Edge(v, w, 0, V[u].head);
V[u].head = top++;
E[top] = Edge(u, 0, 0, V[v].head);
V[v].head = top++;
}
int top;
};
int h[MaxV]; //高度
int path[MaxV]; //回路
int gap[MaxV]; //gap优化
int cur[MaxV]; //当前弧优化
int s, t;
int vexNum, edgeNum;
Graph g;
void setHeight()
{
CLR(gap, 0);
CLR(h, -1);
h[t] = 0;
queue<int>Q;
Q.push(t);
while(!Q.empty())
{
int top = Q.front();
gap[ h[top] ]++;
for(int i = g.V[top].head; i != -1; i = g.E[i].next)
{
int v = g.E[i].v;
if(h[v] == -1)
{
h[v] = h[top] + 1;
Q.push(v);
}
}
Q.pop();
}
}
int sap()
{
setHeight();
int maxFlow = 0, u = s;
int flow = INF;
for(int i = 0; i <= vexNum; i++)
cur[i] = g.V[i].head;
while(h[s] < vexNum)
{
int &i = cur[u];
for(; i != -1; i = g.E[i].next)
{
int v = g.E[i].v;
if(g.E[i].c > g.E[i].f && h[u] == h[v] + 1)
{
u = v;
path[v] = i;
flow = min(flow, g.E[i].c - g.E[i].f);
if(u == t)
{
while(u != s)
{
int j = path[u];
g.E[j].f += flow;
g.E[j ^ 1].f -= flow;
u = g.E[j ^ 1].v;
}
maxFlow += flow;
flow = INF;
}
break;
}
}
if(i == -1)
{
if(--gap[ h[u] ] == 0)
break;
int minH = vexNum - 1;
cur[u] = g.V[u].head;
for(int j = g.V[u].head; j != -1; j = g.E[j].next)
if(g.E[j].c > g.E[j].f)
minH = min(minH, h[g.E[j].v]);
h[u] = minH + 1;
++gap[ h[u] ];
if(u != s)
u = g.E[path[u] ^ 1].v;
}
}
return maxFlow;
}
int main()
{
int ncase, tmp = 1;
scanf("%d", &ncase);
while(ncase--)
{
g.init();
scanf("%d %d", &vexNum, &edgeNum);
while(edgeNum--)
{
int u, v, w;
scanf("%d %d %d", &u, &v, &w);
g.addEdge(u, v, w);
}
s = 1, t = vexNum;
printf("Case %d: %d\n", tmp++, sap());
}
return 0;
}
spa邻接表参考: http://blog.youkuaiyun.com/dgq8211/article/details/7799229
ek 算法是用邻接矩阵实现是100多ms, 而用邻接表是200多ms
用dinic算法只用了邻接表, 是600+ ms
用SAP 的邻接矩阵是 100+, 邻接表也是100+;
看来SAP算法还是比较不错的