最大流问题Ford-Fulkerson算法

最大传输量

网络中有两台计算机s和t,现在想从s传输数据到t。该网络中一共有N台计算机,其中一些计算机之间连有一条单向的通信电缆,每条通信电缆都有对应的1秒钟内所能传输的最大数据量。当其他计算机之间没有数据传输时,在1秒钟内s最多可以传送多少数据到t?

将上述网络当做一个有向图。图中每条边e都有对应的最大可能的数据传输量。这样就可以把问题转为如下形式:

(1)记每条边对应的实际数据传输量为f(e)。

(2)传输量应该满足如下限制:

            0<=f(e)<=c(e)

(3)数据在传输过程中既不会增加也不会减少,收到的数据量和发出的数据量应该相等。

目标是:最大化从s发出的数据量。

我们称使得传输量最大的f为最大流,而求解最大流的问题为最大流问题。此外,我们称c为边的容量,f为边的流量,s为源点,t为汇点。

(一)贪心算法

(1)找一条s到t 的只经过f(e)<c(e)的边的路径;

扫描二维码关注公众号,回复: 157284 查看本文章

(2)如果不存在满足条件的路径,则结束算法。否则,沿着该路径尽可能地增加,返回第(1)步。


但是得到的结果并非最优的。将最优结果和贪心算法结果的流量求差,得到差值图,可以发现,如果将差值为-1的流给推回去,而得到新的流。

于是将贪心算法做如下改进:

(1)只利用满足f(e)<c(e)的e或者f(e)>0的e对应的反向边rev(e),寻找一条s到t的路径。

(2)如果不存在满足条件的路径,则结束。否则,沿着该路径尽可能地增加流,返回第(1)步。

注:我的理解:可以先按照贪心算法,把结果求出来,然后把结果中流量不为0的边加一条反向边,继续使用算法,看还是否能求出一条新的路径。

残余网络:考虑的f(e)<c(e),和满足f(e)>0的e对应的反向边rev((e)所组成的图

下面是一个Ford-Fulkerson算法的邻接表实现的例子,这里没有保存f(e)的值,取而代之的是直接改变c(e)的值

//用于表示边的结构体(终点,容量,反向边)

struct edge{int to,cap,rev};

vector<edge> G[MAX_V];//图的邻接表表示

bool used[MAX_V];//DFS中用到的访问标记

//向图中增加一条从s到t容量为cap的边

void add_edge(int from,int to,int cap){

  G[from].push_back{(edge){to,cap,G[to].size()}};

  G[to].push_back{(edge){from,0,G[from].size-1}};

}

//通过DFS寻找增广路

int dfs(int v,int t,int f){

if(v==t) return f;

used[v]=true;

for(int i=0;i<G[v].size();i++){

edge &e=G[v][i];

if(!used[G.to]&&e.cap>0){

int d=dfs(e.to,t,min(f,e.cap));

     if (d>0){

e.cap=e.cap-d;

G[e.to][e.rev].cap+=d;

return d;

}

}

}

return 0;

}

//求解从s到t的最大流

int max_flow(int s,int t){

int flow=0;

for(; ;){

memset(used,0,sizeof(used));

int f=dfs(s,t,INF);

int(f==0) return flow;

flow+=f;

}

}


猜你喜欢

转载自blog.csdn.net/u013177799/article/details/74974557