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

懵懂的女人 提交于 2019-11-29 09:51:36

// 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 文件

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!