• 图论学习 c++Ford-Fulkerson 方法


    Ford-Fulkerson算法是用于求解最大流问题的一种经典算法。其核心思想是通过不断寻找增广路径来增加流量,直到找不到增广路径为止。每次找到一条增广路径,就增加相应的流量,更新残余网络。简单来说就是Ford-Fulkerson算法的工作过程,即不断寻找增广路径并增加流量,直到无法找到增广路径为止。

    算法步骤

    1. 初始化: 将所有边的流量初始化为0。
    2. 寻找增广路径: 使用深度优先搜索(DFS)或广度优先搜索(BFS)在残余网络中寻找从源点到汇点的增广路径。
    3. 增广路径上增加流量: 在找到的增广路径上增加可以增加的最小流量。
    4. 更新残余网络: 根据增广路径上的流量调整残余网络。
    5. 重复步骤2-4,直到找不到增广路径为止。

    以一个简单的例子来演示Ford-Fulkerson算法的执行过程。

    假设有一个流网络如下:

    1. 源点 (S)
    2. / \
    3. 10 5
    4. / \
    5. A B
    6. \ /
    7. 5 10
    8. \ /
    9. C
    10. |
    11. 10
    12. |
    13. 汇点 (T)

    其中每条边的数字表示容量。

    步骤1:初始化

    • 所有边的流量初始化为0。

    步骤2:寻找增广路径

    • 使用DFS或BFS从源点S寻找增广路径。假设我们使用DFS找到路径S -> A -> C -> T,路径上的容量为10,最小容量为5。

    步骤3:增广路径上增加流量

    • 增加流量5。路径S -> A -> C -> T上各边的流量增加5。
    • 更新后的流量:
      • S -> A 流量为5,剩余容量为5。
      • A -> C 流量为5,剩余容量为0。
      • C -> T 流量为5,剩余容量为5。

    步骤4:更新残余网络

    • 根据增广路径上的流量调整残余网络。增加逆向边用于表示可以回退的流量。
      • 增加逆向边A -> S,容量为5,流量为0。
      • 增加逆向边C -> A,容量为5,流量为0。
      • 增加逆向边T -> C,容量为5,流量为0。

    步骤2:寻找增广路径(继续)

    • 继续寻找另一条增广路径。假设找到路径S -> B -> C -> T,路径上的容量为10,最小容量为5。

    步骤3:增广路径上增加流量

    • 增加流量5。路径S -> B -> C -> T上各边的流量增加5。
    • 更新后的流量:
      • S -> B 流量为5,剩余容量为0。
      • B -> C 流量为5,剩余容量为5。
      • C -> T 流量为10,剩余容量为0。

    步骤4:更新残余网络

    • 根据增广路径上的流量调整残余网络。增加逆向边用于表示可以回退的流量。
      • 增加逆向边B -> S,容量为5,流量为0。
      • 增加逆向边C -> B,容量为5,流量为0。
      • 增加逆向边T -> C,容量为5,流量为0。

    步骤2:寻找增广路径(结束)

    • 继续寻找增广路径,发现没有增广路径了。

    结果

    • 最大流量为10。
    1. #include // 包含输入输出流的头文件
    2. #include // 包含向量容器的头文件
    3. #include // 包含队列容器的头文件
    4. #include // 包含INT_MAX定义的头文件
    5. #include // 包含memset函数的头文件
    6. using namespace std; // 使用标准命名空间
    7. class FordFulkerson {
    8. int V; // 顶点数量
    9. vectorint>> capacity; // 容量矩阵
    10. vectorint>> adj; // 邻接表
    11. // 广度优先搜索(BFS)函数,用于在残余网络中寻找增广路径
    12. bool bfs(vector<int>& parent, int s, int t) {
    13. vector<bool> visited(V, false); // 访问标记数组,初始化为未访问
    14. queue<int> q; // BFS队列
    15. q.push(s); // 源点入队
    16. visited[s] = true; // 标记源点为已访问
    17. parent[s] = -1; // 源点没有父节点
    18. while (!q.empty()) { // 当队列不为空时
    19. int u = q.front(); // 取出队首元素
    20. q.pop(); // 队首元素出队
    21. for (int v : adj[u]) { // 遍历邻接表中的所有邻接节点
    22. if (!visited[v] && capacity[u][v] > 0) { // 如果节点未访问且有剩余容量
    23. if (v == t) { // 如果找到汇点
    24. parent[v] = u; // 记录父节点
    25. return true; // 返回找到增广路径
    26. }
    27. q.push(v); // 将节点入队
    28. parent[v] = u; // 记录父节点
    29. visited[v] = true; // 标记节点为已访问
    30. }
    31. }
    32. }
    33. return false; // 如果没有找到增广路径,返回false
    34. }
    35. public:
    36. // 构造函数,初始化顶点数量、容量矩阵和邻接表
    37. FordFulkerson(int V) : V(V), capacity(V, vector<int>(V, 0)), adj(V) {}
    38. // 添加边及其容量
    39. void addEdge(int u, int v, int cap) {
    40. capacity[u][v] = cap; // 设置容量
    41. adj[u].push_back(v); // 添加邻接点
    42. adj[v].push_back(u); // 添加反向边的邻接点
    43. }
    44. // 计算最大流量
    45. int maxFlow(int s, int t) {
    46. int max_flow = 0; // 初始化最大流量为0
    47. vector<int> parent(V); // 用于记录增广路径中的父节点
    48. while (bfs(parent, s, t)) { // 当找到增广路径时
    49. int path_flow = INT_MAX; // 初始化路径流量为无穷大
    50. // 计算增广路径中的最小流量
    51. for (int v = t; v != s; v = parent[v]) {
    52. int u = parent[v];
    53. path_flow = min(path_flow, capacity[u][v]);
    54. }
    55. // 更新残余网络中的容量
    56. for (int v = t; v != s; v = parent[v]) {
    57. int u = parent[v];
    58. capacity[u][v] -= path_flow;
    59. capacity[v][u] += path_flow;
    60. }
    61. // 增加总流量
    62. max_flow += path_flow;
    63. }
    64. return max_flow; // 返回最大流量
    65. }
    66. };
    67. int main() {
    68. int V = 6; // 顶点数量 (包括源点和汇点)
    69. FordFulkerson graph(V); // 创建一个FordFulkerson对象
    70. // 添加边和对应的容量
    71. graph.addEdge(0, 1, 10); // S -> A 容量 10
    72. graph.addEdge(0, 2, 5); // S -> B 容量 5
    73. graph.addEdge(1, 3, 5); // A -> C 容量 5
    74. graph.addEdge(2, 3, 10); // B -> C 容量 10
    75. graph.addEdge(3, 5, 10); // C -> T 容量 10
    76. int source = 0; // 源点 S
    77. int sink = 5; // 汇点 T
    78. // 计算并输出最大流量
    79. cout << "最大流量: " << graph.maxFlow(source, sink) << endl;
    80. return 0;
    81. }

  • 相关阅读:
    蓝桥杯2024年第十五届省赛
    Python 随机字符串的生成方式
    【计算机组成 课程笔记】7.2 DRAM和SRAM
    Linux网络命令
    git 如何删除本地分支且并没有完全合并到目标分支中
    Hive 数据仓库介绍
    golang如何生成zip压缩文件
    OpenStack裸金属ironic组件web-console界面定制
    Golang数组:全面指南与实际示例
    和平精英中传群岛怎么进 和平精英中传群岛进入攻略
  • 原文地址:https://blog.csdn.net/m0_61862494/article/details/140206855