求最大流的过程,就是不断找到一条源到汇的路径,然后构建残余网络,
再在残余网络上寻找新的路径,使总流量增加,然后形成新的残余网络,
再寻找新路径…..直到某个残余网络上找不到从源到汇的路径为止,最
大流就算出来了。
每次寻找新流量并构造新残余网络的过程,就叫做寻找流量的“增广路径”,也叫“增广”
各种算法的不同之处,也就是在寻找一条从源到汇的过程中进行优化而已
1) DFS
直接用dfs寻找增广路径,直到找不到路
这种算法十分简单,但复杂度高
本来2次就行了,但有可能要200次
2)Edmonds-Karp 最短增广路算法(BFS) O(n*m*m) (n是点数,m是边数)
利用bfs寻找一条增广路径
#include
#include
#include
#include
using namespace std;
const int maxn=300;
const int INF=(1<<30);
int G[maxn][maxn];
int prev[maxn]; //记录前驱节点,记录增广路径
bool vis[maxn];
int Augment(int s,int t,int m) //增广
{
queue Q;
bool isFound=false; //标记是否找到了增广路
memset(vis,false,sizeof(vis));
memset(prev,0,sizeof(prev));
Q.push(s);
vis[s]=true;
while(!Q.empty())
{
int u=Q.front(); Q.pop();
if(u==t) { //找到增广路径了
isFound=true;
break;
}
for(int v=1;v<=m;v++) //注意是从1开始计数的
if(G[u][v]>0&&!vis[v]){
prev[v]=u;
vis[v]=1;
Q.push(v);
}
}
if(!isFound) return 0; //无路可走
int MinFlow=INF;
int u=m;
while(u!=s){ //计算途中最小流
MinFlow=min(MinFlow,G[prev[u]][u]);
u=prev[u];
}
u=m;
while(u!=s){
G[prev[u]][u]-=MinFlow; //更新途径路的流量
G[u][prev[u]]+=MinFlow; //加上反向边
u=prev[u];
}
return MinFlow;
}
int main()
{
int n,m;
while(cin>>n>>m)
{
int u,v,w;
memset(G,0,sizeof(G));
for(int i=0;i>u>>v>>w; //u-->v 上限是w
G[u][v]+=w; //可能有多条边
}
int MaxFlow=0;
int aug;
while(aug=Augment(1,m,m)) //(start,terminal,Node's number)
MaxFlow+=aug; //加上每次增广的流
cout<
3)Dinic 快速网络流算法(BFS+DFS) O(n*n*m) (n是点数,m是边数)
因为上述算法都是找到一条从源到汇的路径并进行增广后,重新回到源点继续寻找路径
但Dinic并不是从头找
Dinic优点如下:
1)结合BFS快速的优点,先用BFS将源点到汇点分层,每次DFS时,只能走到下一层结点
2)因为每次增广后增广路径上至少有一条路径流量上限为0,所以直接返回到增广路径中流量为0的起点进行增广,如果有多条增广路径的流量为0,就选择最上面那一条
#include
#include
#include
#include
using namespace std;
const int maxn=300;
const int INF=(1<<30);
int m,n;
int G[maxn][maxn];
bool vis[maxn];
int layer[maxn]; //记录层次
bool getLayer(int s,int t,int m) //分层
{
queue Q;
memset(layer,0,sizeof(layer));
layer[s]=1;
Q.push(s);
while(!Q.empty())
{
int u=Q.front(); Q.pop();
for(int v=1;v<=m;v++)
if(G[u][v]>0&&!layer[v]){
layer[v]=layer[u]+1;
if(v==t) return true; //一旦到终点m就不必分层了
Q.push(v);
}
}
return false;
}
int Dinic(int s,int t,int m)
{
int MaxFlow=0;
while(getLayer(s,t,m))
{
deque DQ; //保存路径
memset(vis,0,sizeof(vis));
vis[s]=1;
DQ.push_back(1);
while(!DQ.empty())
{
int u=DQ.back();
if(u==t) //找到增广路径了,便找出最小流,更新网络流,添加反向边
{
int MinFlow=INF; //最小流
int pMin; //最小流的上一个节点位置
for(int i=1;i0&&MinFlow>G[u][v]) //找出最小流
{
MinFlow=G[u][v];
pMin=u;
}
}
MaxFlow+=MinFlow; //累加到最大流
for(int i=1;i0&&!vis[v]&&layer[v]==layer[u]+1) //只能走到下一层
{
ok=1;
vis[v]=1;
DQ.push_back(v);
break;
}
if(!ok) DQ.pop_back(); //不能走就pop,换一条路走
}
}
return MaxFlow;
}
int main()
{
while(cin>>n>>m) //从1~m的最大流 //m为顶点数,n为边数
{
int u,v,w;
memset(G,0,sizeof(G));
for(int i=0;i>u>>v>>w; //u-->v 上限是w
G[u][v]+=w; //可能有多条边
}
cout<