网络流之标号法

时隔一个月,杂事也都差不多解决好了,新的学期新的开始。这是我初步学习网络流,为增广路问题做一个小的总结,以后有更好的模板再修改。

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

求最大流流量

#include<stdio.h>
#include<string.h>
#include<math.h>
#include<algorithm>
#define MAXN 1000 //顶点个数最大值
#define INF 1000000  //无穷大
#define MIN(a,b) ((a)<(b)?(a):(b))
struct ArcType
{
    int c,f;//容量,流量
};
ArcType Edge[MAXN][MAXN];
int n,m;    //顶点个数和弧数
int flag[MAXN]; //顶点的状态,三种
int pre[MAXN]; //标号的第一个分量
int alp[MAXN];  //标号的第二个分量,可改进两
int queue[MAXN];    //BFS,模拟队列
int v;  //队头元素
int qs,qe;  //对列头位置,队列尾位置
int i,j;    //循环变量

void ford()
{
    while(1)
    {
        memset(flag,0xff,sizeof(flag));
        memset(pre,0xff,sizeof(pre));
        memset(alp,0xff,sizeof(alp));
        flag[0]=0;pre[0]=0;alp[0]=INF;
        qs=qe=0;
        queue[qe]=0;
        qe++;
        while(qs<qe && flag[n-1]==-1)//汇点未标号
        {
            v=queue[qs];qs++;
            for(i=0;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;
                        alp[i]=MIN(alp[v],Edge[v][i].c-Edge[v][i].f);
                        queue[qe]=i; qe++;
                    }
                    else if(Edge[i][v].c<INF && Edge[i][v].f>0)//反向
                    {
                        flag[i]=0;pre[i]=-v;
                        alp[i]=MIN(alp[v],Edge[i][v].f);
                        queue[qe]=i;    qe++;
                    }
                }
            }
            flag[v]=1;
        }

        if(flag[n-1]==-1 || alp[n-1]==0)
            break;
        int k1=n-1,k2=abs(pre[k1]);
        int a=alp[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;
            k1=k2;k2=abs(pre[k2]);
        }
    }//end of while
    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\n",i,j,Edge[i][j].f);

        }
    }
    printf("%maxFlow:%d\n",maxFlow);
}

int main()
{
    int u,v,c,f;    //弧的起点,终点,容量,流量
    scanf("%d%d",&n,&m);
    for(i=0;i<n;i++)
    {
        for(j=0;j<n;j++)
            Edge[i][j].c=Edge[i][j].f=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();
}


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值