Network Flow 网络流 - Ford Folkerson求最大流

感谢forwiat的博客帮助理解

几个关键点

1.增广路径的满足条件
(1)所有正向边f(u,v) < c(u,v)
(2)所有逆向边 f(u,v) > 0

2.更新 f和c, d是路径上最小的remain_capacity
正向边 f(u,v) = f(u,v)+d    c(u,v) = c(u,v)-d
逆向边f(u,v) = f(u,v)-d     c(u,v)不更新


#include<iostream>
#include<cstring>
#include<string>
#include<queue>
#include<algorithm>
#include<map>
#include<iomanip>
#define inf 0x3f3f3f3f
#define maxn 20
using namespace std;

int capacity[maxn][maxn];  //路径上的最大容量
int flow[maxn][maxn]; //实际的流量
int book[maxn]; //标记一下哪些点已经找过了,后续就不再访问那个点了
int father[maxn]; //用来存放该节点的父节点是谁
typedef struct {
    int point;
    int MIN_remain_capcity;
}Node;
queue<Node> q;

//循环调用BFS知道没有找到一条增广路径,return的返回值是增加的流量
int findAugmentingPath(int start, int end, int n)
{
    memset(book, 0, sizeof(book));
    memset(father, -1, sizeof(father));
    while(!q.empty()) {
        q.pop();
    }
    Node firstPoint;
    firstPoint.point=start;
    firstPoint.MIN_remain_capcity=inf;
    q.push(firstPoint);
    Node front; //存放queue的第一个元素
    while(!q.empty()) {
        front = q.front();
        q.pop();
        for(int i=1;i<=n;i++) {
            //判断两个点之间是否直接相连,且该点之前没有走过
            if(!book[i] && capacity[front.point][i]!=inf) {
                Node next;
                next.point=i;
                next.MIN_remain_capcity=front.MIN_remain_capcity;//把父节点的remain_capacity赋值给当前节点
                if(capacity[front.point][i]>0) {//正向边的情况
                    if(flow[front.point][i] < capacity[front.point][i]) { //f(u,v) < c(u,v)
                        if(front.MIN_remain_capcity > capacity[front.point][i]) { //计算最小的remain_capacity
                            next.MIN_remain_capcity=capacity[front.point][i];
                        }
                        father[i]=front.point;//可以找到父节点,为了最后找汇点的时候进行remain_capacity的更新
                        book[i]=1;
                        q.push(next);
                        //如果找到汇点,则返回拿到的最小capacity,并且更新原有的capacity
                        if(i==end) {
                            cout<<"find"<<endl;
                            int p=i;
                            while(p!=-1) { //更新原来路径的remain_capacity和flow
                                cout<<p<<" ";
                                capacity[father[p]][p] -= next.MIN_remain_capcity; //更新remain_capacity
                                capacity[p][father[p]] = capacity[father[p]][p];
                                //之所以更新flow数组,是因为前面会比较flow跟capacity的大小
                                flow[father[p]][p] += next.MIN_remain_capcity; //f(u,v) = f(u,v)+d
                                flow[p][father[p]] = flow[father[p]][p];
                                p=father[p];
                            }
                            cout<<endl;
                            return next.MIN_remain_capcity;//返回最小的remain_capacity
                        }
                    }
                }//逆向边的情况
                else if(capacity[front.point][i]<0) { //这里不直接使用else的原因是还有=0的情况
                    if(flow[front.point][i] > 0) { //f(u,v) >0
                        if(front.MIN_remain_capcity > -capacity[front.point][i]) { //计算最小的remain_capacity
                            next.MIN_remain_capcity=-capacity[front.point][i]; //这里因为是负值,所以加个h负号把它变成正的
                        }
                        father[i]=front.point;//可以找到父节点,为了最后找汇点的时候进行remain_capacity的更新
                        book[i]=1;
                        q.push(next);
                        //如果找到汇点,则返回拿到的最小capacity,并且更新原有的capacity
                        if(i==end) {
                            cout<<"find"<<endl;
                            int p=i;
                            while(p!=-1) { //更新原来路径的remain_capacity和flow, 逆向边不更新remain_capacity
                                //之所以更新flow数组,是因为前面会比较flow跟capacity的大小
                                flow[father[p]][p] -= next.MIN_remain_capcity;
                                flow[p][father[p]] = flow[father[p]][p];
                                cout<<p<<" ";
                                p=father[p];
                            }
                            cout<<endl;
                            return next.MIN_remain_capcity;//返回最小的remain_capacity
                        }
                    }
                }
            }
        }
    }
    return -1;
}


int main()
{
    int n,m,front,to,weight;
    int start, end; //start起点,end终点
    cin>>n>>m;
    cin>>start>>end;
    
    for(int i=0;i<m;i++){
        cin>>front>>to>>weight;
        capacity[front][to]=weight;
        capacity[to][front]=-weight;
    }
    
    int temp=findAugmentingPath(start, end, n);
    int sum=0;
    while(temp != -1){
        sum += temp;
        temp = findAugmentingPath(start, end, n);
        
    }
    cout<<sum<<endl;
    return 0;
}

/*
5 6
1 5
1 2 4
1 3 6
2 3 2
2 4 3
3 5 4
4 5 5
*/
发布了147 篇原创文章 · 获赞 29 · 访问量 10万+

猜你喜欢

转载自blog.csdn.net/Haskei/article/details/102696233
今日推荐