• 网络流(标号法)


    样例输入:

    6 10
    0 1 8 2
    0 2 4 3
    1 3 2 2
    1 4 2 2
    2 1 4 2
    2 3 1 1
    2 4 4 0
    3 4 6 0
    3 5 9 3
    4 5 7 2

    样例输出:

    0->1 : 4
    0->2 : 4
    1->3 : 2
    1->4 : 2
    2->1 : 0
    2->3 : 1
    2->4 : 3
    3->4 : 0
    3->5 : 3
    4->5 : 5
    maxFlow : 8

    #include <cstdio>
    #include <cmath>
    #include <cstring>
    #define MAXN 1000    //顶点个数最大值
    #define INF 1000000    //无穷大
    #define MIN(a,b) ((a)<(b)?(a):(b))
    
    struct ArcType    //弧结构
    {
        int c, f;    //容量,流量
    };
    ArcType Edge[MAXN][MAXN];    //邻接矩阵(每个元素为ArcType类型)
    int n, m;        //顶点个数和弧数
    int flag[MAXN]; //顶点状态:-1-未标号,0-已标号未检查,1-已标号已检查
    int prev[MAXN];    //标号的第一个分量:指明标号从哪个顶点得到,以便找出可改进量
    int alpha[MAXN];    //标号的第二个分量:可改进量α
    int queue[MAXN];    //相当于BFS算法中的队列
    int v;            //从队列里取出来的队列头元素
    int qs, qe;        //队列头位置,队列尾位置
    int i, j;        //循环变量
    
    void ford( )
    {
        while( 1 )    //标号直至不存在可改进路
        {
            //标号前对顶点状态数组初始化
            memset( flag, 0xff, sizeof(flag) );    //将3个数组各元素初始化为-1
            memset( prev, 0xff, sizeof(prev) );  memset( alpha, 0xff, sizeof(alpha) );
            flag[0] = 0;  prev[0] = 0;  alpha[0] = INF; //源点为已标号未检查顶点
            qs = qe = 0; 
            queue[qe] = 0;  qe++;    //源点(顶点0)入队列
            
            //qs<qe表示队列非空, flag[n-1]==-1表示汇点未标号
            while( qs<qe && flag[n-1]==-1 )
            {
                v = queue[qs];  qs++;    //取出队列头顶点
                for( i=0; i<n; i++ )    //检查顶点v的正向和反向"邻接"顶点
                {
                    if( flag[i]==-1 )    //顶点i未标号
                    {
                        //"正向"且未"满"
                        if( Edge[v][i].c<INF && Edge[v][i].f < Edge[v][i].c )
                        {
                            flag[i] = 0;  prev[i] = v;    //给顶点i标号(已标号未检查)
                            alpha[i] = MIN( alpha[v], Edge[v][i].c - Edge[v][i].f );
                            queue[qe] = i;  qe++;    //顶点i入队列
                        }
                        else if( Edge[i][v].c<INF && Edge[i][v].f > 0 )    //"反向"且有流量
                        {
                            flag[i] = 0;  prev[i] = -v;    //给顶点i标号(已标号未检查)
                            alpha[i] = MIN( alpha[v], Edge[i][v].f );
                            queue[qe] = i;  qe++;    //顶点i入队列
                        }
                    }
                }
                flag[v] = 1;    //顶点v已标号已检查
            }//end of while( qs<qe && flag[n-1]==-1 )
    
            //当汇点没有获得标号,或者汇点的调整量为0,应该退出while循环
            if( flag[n-1]==-1 || alpha[n-1]==0 )  break;
            
            //当汇点有标号时,应该进行调整了
            int k1 = n-1, k2 = abs( prev[k1] );
            int a = alpha[n-1];    //可改进量
            while( 1 )
            {
                if( Edge[k2][k1].f<INF ) //正向
                    Edge[k2][k1].f = Edge[k2][k1].f + a;
                else  Edge[k1][k2].f = Edge[k1][k2].f - a;     //反向
                if( k2==0 )  break;    //调整一直到源点v0
                k1 = k2;  k2 = abs( prev[k2] );
            }//end of while( 1 )
        }//end of while( 1 )
    
        //输出各条弧及其流量,以及求得的最大流量
        int maxFlow = 0;
        for( i=0; i<n; i++ )
        {
            for( j=0; j<n; j++ )
            {
                if( i==0 && Edge[i][j].f<INF )    //求源点流出量,即最大流
                    maxFlow += Edge[i][j].f;
                if( Edge[i][j].f<INF )  printf( "%d->%d : %d
    ", i, j, Edge[i][j].f );
            }
        }
        printf( "maxFlow : %d
    ", maxFlow );
    }
    
    void main( )
    {
        int u, v, c, f;    //弧的起点、终点、容量、流量
        scanf( "%d%d", &n, &m );    //读入顶点个数n和弧数m
        for( i=0; i<n; i++ )    //初始化邻接矩阵中各元素
        {
            for( j=0; j<n; j++ )  Edge[i][j].c = Edge[i][j].f = INF;    //INF表示没有直接边连接
        }
        for( i=0; i<m; i++ )    //读入每条弧
        {
            scanf( "%d%d%d%d", &u, &v, &c, &f );    //读入边的起点和终点
            Edge[u][v].c = c;  Edge[u][v].f = f;    //构造邻接矩阵
        }
        ford( );    //标号法求网络最大流
    }
  • 相关阅读:
    bzoj 1051: [HAOI2006]受欢迎的牛
    bzoj 1192: [HNOI2006]鬼谷子的钱袋
    一些动规水题
    USACO 2014 Open Silver Fairphoto
    USACO 2013 Nov Silver Pogo-Cow
    09day1
    09day2
    08day2
    08day1
    07day2
  • 原文地址:https://www.cnblogs.com/Deng1185246160/p/3269477.html
Copyright © 2020-2023  润新知