网络流 之 一般增广路算法 标号法实现

来源:互联网 发布:linux ddos防御 编辑:程序博客网 时间:2024/05/22 03:16

数据输入格式:首先输入顶点个数n和弧数m,然后输入每条弧的数据。规定源点为顶点0,汇点为顶点n-1.每条弧的数据格式为:u,v,c,f,分别表示这条弧的起点,终点,容量和流量。顶点序号从0开始。

代码:

#include <iostream>#include <cstdio>#include <cstring>#include <algorithm>#include <cmath>#include <string>#include <map>#include <stack>#include <vector>#include <set>#include <queue>#pragma comment (linker,"/STACK:102400000,102400000")#define maxn 1005#define MAXN 1000#define mod 1000000009#define INF 0x3f3f3f3f#define pi acos(-1.0)#define eps 1e-6typedef long long ll;using namespace std;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 que[MAXN];  //队列int v;  //从队列中取出来的队列头元素int qs,qe; //队列头位置,队列尾位置int i,j;  //循环变量void ford(){    while (1)  //标号直到不存在可改进路    {        //标号前对顶点状态数组初始化为-1        memset(flag,-1,sizeof(flag));        memset(prev,-1,sizeof(prev));        memset(alpha,-1,sizeof(alpha));        flag[0]=0;  prev[0]=0;  alpha[0]=INF;  //源点为已标号未检查点        qs=qe=0;        que[qe]=0;//源点入队        qe++;  //qs<qe表示队列非空,flag[n-1]==-1表示汇点未标号        while (qs<qe&&flag[n-1]==-1)        {            v=que[qs];  qs++;  //取出队列头顶点            for (i=0;i<n;i++)  //检查顶点v的正向和反向“邻接”顶点            {                if (flag[i]==-1)                {                    //“正向”且未“满”                    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);                        que[qe]=i;  //顶点i入队                        qe++;                    }                    //"反向"且有流量                    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);                        que[qe]=i;  //顶点i入队                        qe++;                    }                }            }            flag[v]=1;        }  //end of while (qs<qe&&flag[n-1]==-1)        //当汇点没有获得标号,或者汇点的调整量为零,应该退出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)   //调整一直到源点0                break;            k1=k2;            k2=abs(prev[k2]);        }    }    //输出各条弧及其流量,以及求得的最大流量    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;  //弧的起点,终点,容量,流量    while (scanf("%d%d",&n,&m)!=EOF)  //读入顶点个数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();    }    return 0;}/*6 100 1 8 20 2 4 31 3 2 21 4 2 22 1 4 22 3 1 12 4 4 03 4 6 03 5 9 34 5 7 2*/


23 0
原创粉丝点击