最大流问题--FF与Dinic算法

// algorithm_FF.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。
//

#include "pch.h"


#include <iostream>
#include <set>
#include <math.h>
#include <algorithm>

//Max stream FF算法
//Matrix  representation

#define inf INT_MAX

//#define N 5


int D[5][5] = { {0,4,6,inf,inf},
                {inf,0,2,3,inf},
                {inf,inf,0,inf,4},
             {inf, inf, inf, 0, 5},
            {inf,inf,inf,inf,0} };

#define N 6
int C[6][6] = { {0,8,12,inf,inf,inf},
                {inf,0,inf,6,10,inf},
                {inf,2,0,10,inf,inf},
             {inf, inf, inf,0, inf, 8},
            {inf,inf,inf,2,0,10},
            {inf,inf,inf,inf,inf,0    } };



struct Edge {
    int c;
    int f;
};
Edge edge[N][N];


int flag[N];//各点是否被标记
int prev[N];//前面一个节点是谁
int delta[N];//到j未止的最小值min(min(all(c-f)),min(f_))
int chain[N];//

void init_edge(int mat[][N])//第二维开始要标记
{
    for (int i = 0; i < N;i++)
    {
        for (int j = 0; j < N; j++)
        {
            if (mat[i][j] != 0 and mat[i][j] < inf)
            {
                edge[i][j].c = mat[i][j];
                edge[i][j].f = 0;
            }
        }

    }

}


const int s = 0;//为什么被改了
const int t = 5;


//using namespace std;

void FF()
{
    
    while (1)
    {
        memset(flag, 0xff, sizeof(flag));//置为-1//表示是否标号.-1为标号,0为已标号未检查,1为标号已检查
        memset(prev, 0xff, sizeof(prev));//置为-1//
        memset(delta, 0xff, sizeof(delta));//置为-1
        flag[s] = 0;//
        prev[s] = 0;
        delta[s] = inf;
        int edge_head = -1;//Delta,书中大写三角形
        int  edge_tail = 0;
        chain[edge_tail] = s;


        while (edge_head < edge_tail)//第一次为0<1;1,3//BFS搜索
        {
            edge_head++;//第一次为1
            int i;
            i = chain[edge_head];//第一次为s,0,1,1//2,2//3,3//4,4//5,5.。/4,3节点//
            for (int j = 1; j < N; j++)
            {
                if (flag[j] == -1)//未被标记者
                {
                    if (edge[i][j].c < inf and edge[i][j].f < edge[i][j].c)//邻接且不饱和
                    {
                        flag[j] = 0;
                        prev[j] = i;
                        delta[j] = std::min(delta[i], edge[i][j].c - edge[i][j].f);
                        chain[++edge_tail] = j;//第一次为edge_tail=2,chain[2]=1;//二:3,2//内存泄露了这里改进了

                    }
                    else if (edge[j][i].c < inf and edge[j][i].f>0)//
                    {
                        flag[j] = 0;
                        prev[j] = -i;
                        delta[j] = std::min(delta[i], edge[j][i].f);
                        chain[++edge_tail] = j;//
                    }

                }
            }
            flag[i] = 1;//表示已经处理????不知道

        }

        if (delta[t] == 0 or flag[t] == -1)//delta[t]=0表示,找不到增广链了出发不了即发点饱和了,flag[t]=-1表示中断了,到不了t了,即不存在增广路径了flag中没有了(已标号未检查)
            break;//结束了
        int k1 = t;
        int k0 = abs(prev[k1]);
        int a = delta[t];
        while (1)//回溯
        {
            if (edge[k0][k1].c < inf)
                edge[k0][k1].f += a;
            else if (edge[k1][k0].c < inf)
                edge[k1][k0].f -= a;
            if (k0 == s)
                break;
            k1 = k0;
            k0 = abs(prev[k1]);
        }
        delta[t] = 0;//新一轮开始



    }

    int f = 0;
    
    for (int j = 1; j < N; j++)
    {    
        if (edge[s][j].f < inf)
            {
                f += edge[s][j].f;
            }
    }
    
    std::cout << "maxflow" << f << std::endl;


}

int main()
{
    int f = 0;
    init_edge(C);
    FF();



    std::cout << "Hello World!\n";
}



/*

#include<vector>
#include <algorithm>
#define maxn 1200
#define INF 2e9
using namespace std;
int i, j, k, n, m, h, t, tot, ans, st, en;
struct node {
    int c, f;
}edge[maxn][maxn];
int flag[maxn], pre[maxn], alpha[maxn], q[maxn], v;
int read() {
    char c; int x; while (c = getchar(), c<'0' || c>'9'); x = c - '0';
    while (c = getchar(), c >= '0'&&c <= '9') x = x * 10 + c - '0'; return x;

}

//两个例子1// 6 9 1 6 1 2 8 1 3 12  2 4 6  2  5 10  3 2  2  3  4 10  4 6 8  5 4 2  5  6 10
//2//5 6 1 5 1 2 4 1 3 6 2 3 2 2 4 3 3 5 4 4 5 5




void bfs() {
    memset(flag, 0xff, sizeof(flag)); memset(pre, 0xff, sizeof(pre)); memset(alpha, 0xff, sizeof(alpha));
    flag[st] = 0; pre[st] = 0; alpha[st] = INF; h = 0, t = 1; q[t] = st;
    while (h < t) {
        h++; v = q[h];
        for (int i = 1; i <= n; i++) {
            if (flag[i] == -1) {
                if (edge[v][i].c < INF&&edge[v][i].f < edge[v][i].c) {
                    flag[i] = 0; pre[i] = v; alpha[i] = min(alpha[v], edge[v][i].c - edge[v][i].f); q[++t] = i;
                }
                else if (edge[i][v].c < INF&&edge[i][v].f>0) {
                    flag[i] = 0; pre[i] = -v; alpha[i] = min(alpha[v], edge[i][v].f); q[++t] = i;
                }
            }
        }
        flag[v] = 1;
    }
}

void Ford_Fulkerson() {
    while (1) {
        bfs();
        if (alpha[en] == 0 || flag[en] == -1) {
            break;
        }
        int k1 = en, k2 = abs(pre[k1]); int a = alpha[en];
        while (1) {
            if (edge[k2][k1].c < INF) edge[k2][k1].f += a;
            else if (edge[k1][k2].c < INF) edge[k1][k2].f -= a;
            if (k2 == st) break;
            k1 = k2; k2 = abs(pre[k1]);
        }
        alpha[en] = 0;
    }
}

void flow() {
    int maxflow = 0;
    for (int i = 1; i <= n; i++)
        for (int j = 1; j <= n; j++) {
            if (i == st && edge[i][j].f < INF) maxflow += edge[i][j].f;
        }
    printf("%d", maxflow);
}

int main() {
    int u, v, c, f;
    n = read(); m = read(); st = read(); en = read();
    for (int i = 1; i <= n; i++)
        for (int j = 1; j <= n; j++) edge[i][j].c = INF, edge[i][j].f = 0;
    for (int i = 1; i <= m; i++) {
        u = read(); v = read(); c = read();
        edge[u][v].c = c;
    }
    Ford_Fulkerson();
    flow();
    return 0;
}
*/

// 运行程序: Ctrl + F5 或调试 >“开始执行(不调试)”菜单
// 调试程序: F5 或调试 >“开始调试”菜单

// 入门提示:
//   1. 使用解决方案资源管理器窗口添加/管理文件
//   2. 使用团队资源管理器窗口连接到源代码管理
//   3. 使用输出窗口查看生成输出和其他消息
//   4. 使用错误列表窗口查看错误
//   5. 转到“项目”>“添加新项”以创建新的代码文件,或转到“项目”>“添加现有项”以将现有代码文件添加到项目
//   6. 将来,若要再次打开此项目,请转到“文件”>“打开”>“项目”并选择 .sln 文件

 

 

//Dinic

#include <iostream>
#include <vector>
#include <algorithm>
#include <climits>
using namespace std;
#define inf 2e9
#define maxN 10005
#define maxM 100005
//#define N 5
/*

int C[5][5] = { {0,4,6,inf,inf},
                {inf,0,2,3,inf},
                {inf,inf,0,inf,4},
                {inf, inf, inf, 0, 5},
                {inf,inf,inf,inf,0} };



                */

//#define N 6
//const int s = 0;//
//const int t = 4;


int s;
int t;
int N;
int M;
/*
int C[6][6] = { {0,8,12,inf,inf,inf},
    {inf,0,inf,6,10,inf},
    {inf,2,0,10,inf,inf},
    {inf, inf, inf,0, inf, 8},
   {inf,inf,inf,2,0,10},
   {inf,inf,inf,inf,inf,0    } };


*/

int m = 0;
int cnt = 0;
vector<int > W, T;
vector<vector<int>> A(maxN);
void preprocess(vector<vector<int>> C)
{
    int ret = 0;
    for (int i = 0; i < N; i++)
    {
        for (int j = 0; j < N; j++)
        {
            if (i != j and C[i][j] < inf)
            {
                ret++;
                int x = i; int y = j; int c = C[i][j];
                W.push_back(c);//W即C,C即W也
                T.push_back(y);//与cnt对应的
                A[x].push_back(cnt);//用于查找x出去的流量
                cnt++;
                W.push_back(0);
                T.push_back(x);//作为反向边也存下来
                A[y].push_back(cnt);//用于查找y出去的流量
                cnt++;




            }
        }
    }
    m = ret;
}



void input()
{
    cin>>N;
    cin>>M;
    cin>>s;
    cin>>t;
    s=s-1;
    t=t-1;
    int ret = M;
    for (int i = 0; i < M; i++)
    {


        int x, y;
        int  c;
        cin >> x >> y >> c;
        x=x-1;
        y=y-1;


        W.push_back(c);//W即C,C即W也
        T.push_back(y);//与cnt对应的
        A[x].push_back(cnt);//用于查找x出去的流量
        cnt++;
        W.push_back(0);
        T.push_back(x);//作为反向边也存下来
        A[y].push_back(cnt);//用于查找y出去的流量
        cnt++;


    }

}


int head = 0, tail = 0;


vector<int > chain(maxM*5, -1);
vector<int> dist(maxN, 0);
bool BFS()
{
    head = -1;
    tail = -1;
    chain[++tail] = s;
    fill(dist.begin(),dist.end(),0);
    dist[0] = 1;
    while (head < tail)
    {
        int i = chain[++head];
        for (int j = 0; j < A[i].size(); j++)
        {
            int y_cnt = A[i][j];
            if (dist[T[y_cnt]]==0 and W[y_cnt])
            {
                dist[T[y_cnt]] = dist[i] + 1;
                chain[++tail] = T[y_cnt];
            }
        }
    }
    return  dist[t];
}

int find(int cur, int  x)
{
    if (cur == t) return x;
    for (int j = 0; j < A[cur].size(); j++)
    {
        int y_index = A[cur][j];
        if (dist[T[y_index]] == dist[cur] + 1 && W[y_index])
        {
            int fd = find(T[y_index], min(x, W[y_index]));
            if (fd)
            {
                W[y_index] -= fd;
                W[y_index ^ 1] += fd;//y_index一定为偶数,^1就是加1
                return fd;
            }
        }
    }
    return 0;
}




int main()
{
    int f = 0;


    input();
    while (BFS() != 0) {
        f += find(s, inf);
    }
    cout << f;
    return 0;
}

转载于:https://www.cnblogs.com/Jonn-Liu/p/11511707.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值