假设从s到t之间所有路径的容量如下图的有向图
如果走s->1->2->t,则这条路径能传输的流量是5。
接着走s->1->3->t,因为 s->1的容量为10,则这次只能传输5,所以按照这种方法从s到t能传输的总流量为10。
用cf[][]数组存储从A->B点的容量
按照上述方法,从1->2的流量为f=5,则将cf[1][2]-=5,此时1->2的残流(即剩余容量)为1,此时反向边2->1的容量
加5,因原本2->1的流量为0,此时c[2][1]=5。
假设所有路径已经结束,此时,cf[1][2]=1,cf[2][1]=5,cf[1][3]=1,cf[3][1]=5
若从2点向1点发出流量,而此时cf[1][2]这条路径为1,找到各个路径中大于0的最小残流量为1,
而在2->1->3->t这条路径中,还可以再多承载1的流量,此时cf[1][2]=4(因为由2向1逆推了1的流量),cf[1][3]=6,
cf[3][t]=6,而此时cf[2][1]=6,cf[2][t]=4.
现在再来观察这张图
此时我们可以发现s->2->t这条路仍旧可以走,此时cf[2][t]=4,未饱和,找到此时路径中的最小残流量为1,
从s向2发出1的流量,这时cf[2][t]这条路径饱和,这时候可以发现,从s到t可以传输的总流量为11
/***********************************************************/
BFS(Edmonds_Karp算法)
#include<stdio.h>
#include<string.h>
#include<queue>
#include<algorithm>
using namespace std;
#define INF 0x3f3f3f3f
int f,flow[210][210],cap[210][210],a[210];
int m,n,p[210];
void bfs()
{
int s=1;
f=0;
queue<int>q;
for(;;)
{
memset(a,0,sizeof(a));
a[s]=INF;
q.push(s);
while(!q.empty())
{
int u=q.front();
q.pop();
for(int v=1; v<=n; v++)
{
if(!a[v] && cap[u][v] > flow[u][v])
{
a[v]=min(a[u],cap[u][v]-flow[u][v]);
p[v]=u; //记录v的父亲,并加入队列
q.push(v);
}
}
}
if(a[n]==0)//若找不到说明已经是最大流
break;
for(int i=n; i!=s; i=p[i]) //从汇点逆行
{
flow[p[i]][i]+=a[n]; //更新正向流量
flow[i][p[i]]-=a[n]; //更新反向流量
}
f+=a[n];
}
}
int main()
{
int a,b,c;
while(~scanf("%d%d",&m,&n))
{
memset(flow,0,sizeof(flow));
memset(cap,0,sizeof(cap));
for(int i=0; i<m; i++)
{
scanf("%d%d%d",&a,&b,&c);
cap[a][b]+=c;
}
bfs();
printf("%d\n",f);
}
return 0;
}
/*********************************************************************************/
DFS模板(书上的)
#include<vector>
#include<stdio.h>
#include<string.h>
#include<algorithm>
using namespace std;
#define INF 0x3f3f3f3f
struct edge //用于表示边的结构体(终点,容量,反向边)
{
int to,cap,rev;
};
vector<edge> G[201];
int book[201];
int dfs(int v,int t,int f) //通过DFS寻找增广路
{
if(v==t)
return f;
book[v]=1;
for(int i=0; i<G[v].size(); i++)
{
edge &e=G[v][i];
if(!book[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;
}
int max_flow(int s,int t) //求解从s到t的最大流
{
int flow=0;
for(;;)
{
memset(book,0,sizeof(book));
int f=dfs(s,t,INF);
if(f==0)
return flow;
flow+=f;
}
}
int main()
{
int n,m;
int from,to,cap;
while(~scanf("%d%d",&n,&m))
{
for(int i=1; i<=m; i++)
G[i].clear();
for(int i=0; i<n; i++)
{
scanf("%d%d%d",&from,&to,&cap);
G[from].push_back((edge)
{
to,cap,G[to].size() //G[to].size()指反向边存放的位置
});
G[to].push_back((edge)
{
from,0,G[from].size()-1
});
}
printf("%d\n",max_flow(1,m));
}
return 0;
}
/*******************************************************************/
DFS(在网上看到的大牛写的代码)
#include<cstdio>
#include<cstring>
#define N 201
int n; //有向边数
int m; //顶点数
int f[N][N]; //网络流
int cf[N][N]; //残留网络
bool vis[N]; //DFS中是否访问过
const int inf =1<<29;
int inline min(intx,int y)
{
return x>y?y:x;
}
bool dfs(int s,intt,int &cf_path)
{
vis[s]=true;
if(s==t)
return true;
for(int i=1; i<=m; ++i)
{
if(vis[i]==false &&cf[s][i]>0)
{
int temp = cf_path;
cf_path=min(cf_path,cf[s][i]);//(a)式
if(dfs(i,t,cf_path))
{
f[s][i]+=cf_path; //更新发出的总流量,因为发出的和收到的总是相等的
cf[s][i]-=cf_path;
cf[i][s]+=cf_path; //允许“反悔”
return true;
}
//沿着<s,i>向下深搜失败,回溯时恢复增广路径的残留容量cf[path];
//实际上是在撤销(a)式的影响!
cf_path = temp;
}
}
return false;
}
int find(int s=1,intt=m) //这实际上是DFS的外围框架(回忆DFS算法实现有内外两层)
{
int cf_path = inf; //本次可增广的流量,在DFS过程中被限制得越来越小
memset(vis,0,sizeof(vis));
dfs(s,t,cf_path);
if(cf_path>=inf)
return 0;
else
return cf_path;
}
int max_flow()
{
int ret=0,i;
memset(f,0,sizeof(f));
while(find());
for(i=1; i<=m; ++i)
ret+=f[1][i]; //网络流的值=从源出发的流量和f(s,V)=流入汇点的流量和f(V,t)
return ret;
}
int main(void)
{
int i,x,y,z;
while(scanf("%d%d",&n,&m)!=EOF)
{
memset(cf,0,sizeof(cf));
for(i=0; i<n; ++i)
{
scanf("%d%d%d",&x,&y,&z);
cf[x][y]+=z;
}
printf("%d\n",max_flow());
}
return 0;
}