题意:现在有m个池塘(从1到m开始编号,1为源点,m为汇点),及n条水渠,给出这n条水渠所连接的池塘和所能流过的水量,求水渠中所能流过的水的最大容量.
Edmonds-Karp算法:
#include
#include
#include
#include
#include
#include
using namespace std;
const int INF = 0x3f3f3f3f;
const int maxn = 505;
int g[maxn][maxn], n, m;
int path[maxn], flow[maxn];
int start, endd;
int bfs()
{
queue q;
memset(path, -1, sizeof(path));
path[start] = 0, flow[start] = INF; // 起始容量为inf
q.push(start);
while(!q.empty())
{
int t = q.front(); q.pop();
if(t == endd) break;
for(int i = 1; i <= m; i++) // 遍历可走路径;
{
if(i!=start && path[i]==-1 && g[t][i]) // 符合这三种情况表示该路径可走
{
flow[i] = min(flow[t], g[t][i]);
q.push(i);
path[i] = t;
}
}
}
if(path[endd] == -1) return -1; // 说明没有找到可走路径,返回-1;
return flow[endd]; // 找到一条路径之后的增流量;
}
int E_K()
{
int max_flow = 0, step, now, pre;
while((step=bfs()) != -1)// 找不到路径之后便退出;
{
max_flow += step; // 累加流量
now = endd;
while(now != start) // 将找到的路径进行反向处理,并更新实际容量;
{
pre = path[now];
g[pre][now] -= step; // 更新正向边的实际容量;
g[now][pre] += step;// 添加反向边
now = pre;
}
}
return max_flow;
}
int main(void)
{
while(cin >> n >> m)
{
memset(g, 0, sizeof(g));
for(int i = 1; i <= n; i++)
{
int u, v, w;
scanf("%d%d%d", &u, &v, &w);
g[u][v] += w;
}
start = 1, endd = m;
printf("%d\n", E_K());
}
return 0;
}
Ford-Fulkerson的dfs写法:(白书上有)
#include
#include
#include
#include
#include
using namespace std;
typedef long long ll;
const int maxn = 505;
const int INF = 0x3f3f3f3f;
int n, m;
bool vis[maxn];
struct node
{
int to, cap, rev; //终点,容量,反向边
node() {}
node(int tt, int cc, int rr): to(tt), cap(cc), rev(rr) {}
};
vector g[maxn];
int dfs(int v, int t, int f)
{
if(v == t) return f;
vis[v] = 1;
for(int i = 0; i < g[v].size(); i++)
{
node &e = g[v][i]; //一定要带&,因为要对他进行修改
if(!vis[e.to] && e.cap > 0)
{
int d = dfs(e.to, t, min(f, e.cap));
if(d > 0)
{
e.cap -= d;
g[e.to][e.rev].cap += d;
return d;
}
}
}
return 0;
}
ll max_flow(int s, int t)
{
ll flow = 0;
while(1)
{
memset(vis, 0, sizeof(vis));
int f = dfs(s, t, INF);
if(!f) return flow;
flow += f;
}
}
int main(void)
{
while(cin >> n >> m)
{
for(int i = 0; i < maxn; i++)
g[i].clear();
for(int i = 0; i < n; i++)
{
int u, v, w;
scanf("%d%d%d", &u, &v, &w);
g[u].push_back(node(v, w, g[v].size()));
g[v].push_back(node(u, 0, g[u].size()-1));
}
printf("%lld\n", max_flow(1, m));
}
return 0;
}
SAP模板:
#include
#include
#include
#include
using namespace std;
const int INF = 0x7fffffff;
const int maxv = 2600;
const int maxe = 1000000;
int n,m;
struct Edge
{
int v;
int next;
int flow;
};
Edge e[maxe];
int head[maxv],edgeNum;
int now[maxv],d[maxv],vh[maxv],pre[maxv],preh[maxv];
void addEdge(int a,int b,int c)
{
e[edgeNum].v = b;
e[edgeNum].flow = c;
e[edgeNum].next = head[a];
head[a] = edgeNum++;
e[edgeNum].v = a;
e[edgeNum].flow = 0;
e[edgeNum].next = head[b];
head[b] = edgeNum++;
}
void Init()
{
edgeNum = 0;
memset(head,-1,sizeof(head));
memset(d,0,sizeof(d));
}
int sap(int s,int t,int n) //源点,汇点,结点总数
{
int i,x,y;
int f,ans = 0;
for(i = 0; i < n; i++)
now[i] = head[i];
vh[0] = n;
x = s;
while(d[s] < n)
{
for(i = now[x]; i != -1; i = e[i].next)
if(e[i].flow > 0 && d[y=e[i].v] + 1 == d[x])
break;
if(i != -1)
{
now[x] = preh[y] = i;
pre[y] = x;
if((x=y) == t)
{
for(f = INF,i=t; i != s; i = pre[i])
if(e[preh[i]].flow < f)
f = e[preh[i]].flow;
ans += f;
do
{
e[preh[x]].flow -= f;
e[preh[x]^1].flow += f;
x = pre[x];
}while(x!=s);
}
}
else
{
if(!--vh[d[x]])
break;
d[x] = n;
for(i=now[x]=head[x]; i != -1; i = e[i].next)
{
if(e[i].flow > 0 && d[x] > d[e[i].v] + 1)
{
now[x] = i;
d[x] = d[e[i].v] + 1;
}
}
++vh[d[x]];
if(x != s)
x = pre[x];
}
}
return ans;
}
int main(void)
{
int n, m;
while(cin >> n >> m)
{
Init();
while(n--)
{
int u, v, w;
scanf("%d%d%d", &u, &v, &w);
addEdge(u, v, w);
}
printf("%d\n", sap(1, m, m));
}
return 0;
}
Sample Input
5 4
1 2 40
1 4 20
2 4 20
2 3 30
3 4 10
Sample Output
50