您的位置:首页 > 理论基础 > 计算机网络

Dinic算法(网络流,最大流)

2016-08-12 11:37 411 查看
Dinic算法是用来解决网络流问题的经典算法,时间效率很快,还可以支持重边。下面让我来介绍一下Dinic算法。

首先,定义弧:

struct edge{
int from , to , cap , flow;
};


Dinic算法就是不断用BFS构造层次图,然后用DFS进行增广。那么,什么是层次图呢?

设dist(u)为原点s到节点u的距离,那么,层次图就是只保留满足dist(u)+1 = dist(u1)的边(u,u1)。


这是一个层次图。

而层次图可以用BFS在残留网络的基础上构造。

bool BFS()
{
memset(vis,0,sizeof(vis));
queue<int> q;//模拟BFS
q.push(s);
d[s] = 0;
vis[s] = 1;
while(!q.empty())//队列非空
{
int x = q.front(); q.pop();
for(int i=0;i<f[x].size();i++)
{
edge &e = edges[f[x][i]];

if(!vis[e.to] && e.flow < e.cap) //只考虑残留网络中的弧
{
vis[e.to] = 1;
d[e.to] = d[x] + 1;//层次图
q.push(e.to);
}
}
}
return vis[t];//能否到汇点,不能就结束
}


假如还存在s-t的路径,我们为了方便,可以用DFS进行多路增广。DFS过程出了当前节点以外,还要看看目前所有弧的最小残量a是否为0,当x为汇点或a为0是终止DFS。

int DFS(int x,int a)//x为当前节点,a为当前最小残量
{
if(x == t || a == 0) return a;
int flow = 0 , r;

for(int& i = cur[x];i < f[x].size();i++)
{
edge& e = edges[f[x][i]];
if(d[x] + 1 == d[e.to] && (r = DFS(e.to , min(a,e.cap - e.flow) ) ) > 0 )
{
e.flow += r;
edges[f[x][i] ^ 1].flow -= r;
flow += r;//累加流量
a -= r;
if(a == 0) break;
}
}
return flow;
}
至此,整个Dinic算法都清晰了。下面给出程序:

#include <cstdio>
#include <cstring>
#include <iostream>
#include <queue>
#include <vector>

using namespace std;

const int Maxn = 10000 + 10;
const int INF = 0x6fffffff >> 2;

struct edge{ int from , to , cap , flow; };

struct Dinic{
int n,m,s,t;
vector<edge> edges;
vector<int> f[Maxn];
bool vis[Maxn];
int d[Maxn];
int cur[Maxn];

void AddEdge(int from,int to,int cap)
{
edges.push_back((edge){from,to,cap,0});
edges.push_back((edge){to,from,0,0});
m = edges.size();
f[from].push_back(m-2);
f[to].push_back(m-1);
}

bool BFS()
{
memset(vis,0,sizeof(vis));
queue<int> q;
q.push(s);
d[s] = 0;
vis[s] = 1;
while(!q.empty())
{
int x = q.front(); q.pop();
for(int i=0;i<f[x].size();i++)
{
edge &e = edges[f[x][i]];
//cout<<"to="<<e.to<<"from="<<e.from<<' '<<e.flow<<' '<<e.cap<<' '<<vis[e.to]<<endl;
if(!vis[e.to] && e.flow < e.cap) //只考虑残留网络中的弧
{
vis[e.to] = 1;
d[e.to] = d[x] + 1;//层次图
q.push(e.to);
}
}
}
return vis[t];//能否到汇点,不能就结束
}
int DFS(int x,int a)//x为当前节点,a为当前最小残量 { if(x == t || a == 0) return a; int flow = 0 , r; for(int& i = cur[x];i < f[x].size();i++) { edge& e = edges[f[x][i]]; if(d[x] + 1 == d[e.to] && (r = DFS(e.to , min(a,e.cap - e.flow) ) ) > 0 ) { e.flow += r; edges[f[x][i] ^ 1].flow -= r; flow += r;//累加流量 a -= r; if(a == 0) break; } } return flow; }
int MaxFlow(int s,int t)
{
this->s = s; this->t = t;
int flow = 0;
while(BFS())
{

memset(cur,0,sizeof(cur));
flow += DFS(s,INF);
}
return flow;
}
}G;

int main()
{
int x,y,z;
int s,t;
scanf("%d",&G.n);
while(1)
{
scanf("%d%d%d",&x,&y,&z);
if(!(x|y|z)) break;
G.AddEdge(x,y,z);
}
scanf("%d%d",&s,&t);
printf("%d\n",G.MaxFlow(s,t));
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息