网络流模板

#include<stdio.h>
#include<string.h>
#include<math.h>
#include<cmath>
#include<cstdio>
#include<cstring>
#define N 10005
#define X 1000000
#define mem(a) memset(a,-1,sizeof(a))
#include<algorithm>
using namespace std;
struct node
{
    int c,f;//容量和流量
};
node Edge[N][N];//邻接矩阵
int n;//顶点个数
int flag[N];//顶点状态,-1未标记,0已标记未检查,1已标记已检查
int prev[N];//标号的第一个分量:指明标号从哪个顶点得到,以便找出可改进量
int alpha[N];//标号的第二个分量,可改进a
int queue[N];//队列模拟
int head,tail;
void ford()
{
    while(1)
    {
        mem(flag),mem(prev),mem(alpha);//初始化
        flag[0]=0,prev[0]=0,alpha[0]=X;//源点处理
        head=tail=0;
        queue[tail++]=0;
        while(head<tail&&flag[n-1]==-1)//队列不为空&&汇点未标号
        {
            int v=queue[head++];
            for(int i=0; i<n; i++)//检查顶点v的正向和反向邻接顶点
            {
                if(flag[i]==-1)//顶点i未标号
                {
                    if(Edge[v][i].c<X&&Edge[v][i].f<Edge[v][i].c)//正向且未满
                    {
                        flag[i]=0;
                        prev[i]=v;
                        alpha[i]=min(alpha[v],Edge[v][i].c-Edge[v][i].f);
                        queue[tail++]=i;
                    }
                    else if(Edge[i][v].c<X&&Edge[i][v].f>0)//反向且有流量
                    {
                        flag[i]=0;//给顶点标号(已标未检查)
                        prev[i]=-v;
                        alpha[i]=min(alpha[v],Edge[i][v].f);
                        queue[tail++]=i;
                    }
                }
            }
            flag[v]=1;//顶点v已标号已检查
        }
        if(flag[n-1]==-1||alpha[n-1]==0)break;//当汇点没有获得标号或者汇点调整量为0,退出循环
        int a=alpha[n-1];/*可改进量*/
//        int k1=n-1,k2=abs(prev[k1]);
//        while(1)
//        {
//            if(Edge[k2][k1].f<X)
//                Edge[k2][k1].f+=a;//正向
//            else
//                Edge[k1][k2].f-=a;//反向
//            if(k2==0)
//                break;
//            k1=k2;
//            k2=abs(prev[k2]);
//        }
        for(int j=n-1,i=abs(prev[j]); ; j=i,i=abs(prev[i]))//调整一直到源点
        {
            if(Edge[i][j].f<X)
                Edge[i][j].f+=a;//正向
            else
                Edge[j][i].f-=a;//反向
            if(i==0)
                break;
        }
    }
    int maxx=0;
    for(int i=0; i<n; i++)
        for(int j=0; j<n; j++)
        {
            if(i==0&&Edge[i][j].f<X)//求源点流出量
                maxx+=Edge[i][j].f;
            if(Edge[i][j].f<X)
                printf("%d->%d : %d\n",i,j,Edge[i][j].f);
        }
    printf("%d\n",maxx);
}
int main()
{
    int u,v,c,f;//弧起点,重点,容量,流量
    scanf("%d",&n);
    for(int i=0; i<n; i++)
        for(int j=0; j<n; j++)
            Edge[i][j].c=Edge[i][j].f=X;//表示没有直接边连接
    while(~scanf("%d%d%d%d",&u,&v,&c,&f)&&(u!=-1||v!=-1||c!=-1||f!=-1))//构造邻接矩阵
    {
        Edge[u][v].c=c;
        Edge[u][v].f=f;
    }
    ford();//标号法求网络最大流
}
//6
//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
//-1 -1 -1 -1

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值