算法实现(1):Ford-Fulkerson Algorithm

来源:互联网 发布:php array slice 编辑:程序博客网 时间:2024/05/16 08:51

一、算法介绍

Ford-Fulkerson算法是一种最大流算法,其核心是通过引入“反向边”及“剩余图”的概念对原先的运输方案进行纠错、改进。引用卜东波老师“计算机算法设计与分析”讲义的描述如下:Ford-Fulkerson 算法引入反向边,让运出去的货物还可以有机会退回。将加入了退货边的图称为剩余图,构造剩余图的大致思路为,若 u → v 运了 f 吨货物,且容量限制为 C(u, v),则剩余图中 u 到 v 的正向弧 u → v 权值为 C(u, v) − f,表示最多还可再运 C(u, v) − f 吨货,并构造权值为 f 的反向弧,表示最多可退大小为f 的货物。

例如,下面两个图分别代表网络的流图及剩余图(剩余图中红色的边为“反向边”,即退货边)

流图及剩余图

Ford-Fulkerson算法过程的示意图如下:

Ford-Fulkerson算法过程

简单来说,就是原始流 + 剩余图中的可行路 = 原始流的一个改进。

二、Pseudo Code

令 p 表示剩余图 Gf 中的一条简单路径,称为增广路径。并定义 bottleneck(p, f) 为路径 p 上的最小容量边。则 Ford-Fulkerson 算法可以描述为:

这里写图片描述

算法开始,首先将所有边上的流量初始化为零,此时剩余图与原流图相同,然后进入循环,只要在剩余图中存在一条从s(源点)到t(终点)的路径,算法就执行以下步骤:任选一条s-t的路径,确定选择的s-t路径上的bottleneck(即该路径所包含的边的剩余流量的最小值),在该条路径上再流最小的剩余流量(即bottleneck值),最后更新流图及剩余图。直至在剩余图中不存在任何的s到t的路径,终止循环。

三、算法实现

1.实现环境:Windows 8, VS 2010;

2.图的数据结构——邻接矩阵:

本博文对算法的实现过程,采用邻接矩阵存储图信息,邻接矩阵存储图信息的详细过程参阅“图的存储表示——邻接矩阵”;

3.完整程序详见Github,以下记录实现过程的难点:

(1) s-t路径搜索

程序中采用DFS(深度优先)算法搜索剩余图中的s-t路径,实际上是一种递归的思路,不断考察当前节点的邻居节点,看是否能到达终点t,若可以返回true,若不行则返回前一节点并考察前一节点的其他邻居节点。

/************************************************************************/  /* 深度优先遍历(深度优先搜索)                                         */  /************************************************************************/  bool Graph::dfs(int source, bool* visited)  {      // if current node is the destination node (t), then s-t path is found    if(source == nodeNum - 1)        return true;    int destination;      visited[source] = true;              for(destination = 0; destination < nodeNum; destination++)  // search node adjacent to source      {        // find adjacent node which has not been visited        if(edge[source][destination]>0  && !visited[destination])          {            // length of current path increase            pathLength += 1;            // add adjacent node to s-t path            path[pathLength-1] = destination;             // go on searching adjacent node            if( !(this -> dfs(destination, visited)) )            {                // if current adjacent node could not reach the final destinated node                // pathLength decrease since it was increased presiously                // continue to investigate the next adjacent node                pathLength -= 1;                continue;            }            else            {                // if current adjacent node could reach the final destinated node                return true;            }        }        else if(destination == nodeNum - 1)            // no adjacent node, means no s-t path            return false;    }//end for} 

(2) 主函数

以前文图示例子作测试,while循环中不断搜索s-t路径,直到剩余图中找不到s-t路径。当存在s-t路径时,如算法所述,取一s-t路径,找bottleneck,更新流与剩余图。

int main(){    // graph wiht node s, u, v, t    char nodeName[nodeNum] = {'s', 'u', 'v', 't'};    Graph graph = Graph(nodeNum);    graph.setNode(nodeName);    graph.setEdge('s', 'u', 1);    graph.setEdge('s', 'v', 1);    graph.setEdge('u', 'v', 1);    graph.setEdge('u', 't', 1);    graph.setEdge('v', 't', 1);    // Ford-Fulkerson algorithm find maximum flow    while(graph.findPath())    {        graph.printPath();        graph.findBottleneck();        graph.update();    }    // print maximum flow    cout << "max flow: " << graph.getFlow() << endl;    system("pause");    return 0;}

四、实现结果

打印算法实现的中间结果如下:
算法实现结果

0 0
原创粉丝点击