网络流之 最短增广路算法模板(SAP)

来源:互联网 发布:淘宝号星级怎么算的 编辑:程序博客网 时间:2024/06/12 00:24

数据输入格式:首先输入顶点个数n和弧数m,然后输入每条弧的数据。规定源点为顶点0,汇点为顶点n-1.每条弧的数据格式为:u,v,w,分别表示这条弧的起点,终点,容量。顶点序号从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 2005#define mod 1000000009#define INF 0x3f3f3f3f#define pi acos(-1.0)#define eps 1e-6typedef long long ll;using namespace std;int d[maxn];    //标号int mp[maxn][maxn];     //残留网络,初始为原图int num[maxn];      //num[i]表示标号为i的顶点数有多少int pre[maxn];      //记录前驱int n,m,s,t;        //n个顶点,m条边,源点s,汇点tvoid init()     //bfs计算标号,汇点t的标号为零{    int k;    queue<int>Q;    memset(d,INF,sizeof(d));  //初始化d数组为无穷大    memset(num,0,sizeof(num));  //初始化num数组num    Q.push(t);      //汇点t入队列    d[t]=0;     //汇点标号为零    num[0]=1;   //标号为0的顶点数为1    while (!Q.empty())    {        k=Q.front();        Q.pop();        for (int i=0;i<n;i++)        {            if (d[i]>=n&&mp[i][k]>0)            {                d[i]=d[k]+1;                Q.push(i);                num[d[i]]++;            }        }    }}int findAlowArc(int i)      //从i出发寻找允许弧{    int j;    for (j=0;j<n;j++)        if (mp[i][j]>0&&d[i]==d[j]+1)            return j;    return -1;}int reLable(int i)      //重新标号{    int mm=INF;    for (int j=0;j<n;j++)        if (mp[i][j]>0)            mm=min(mm,d[j]+1);    return mm==INF?n:mm;}int maxFlow(int s,int t)       //求从源点s出发的最大流{    int flow=0,i=s,j;    int delta;          //增量    memset(pre,-1,sizeof(pre));    while (d[s]<n)    {        j=findAlowArc(i);        if (j>=0)        {            pre[j]=i;            i=j;            if (i==t)       //更新残留网络            {                delta=INF;                for (i=t;i!=s;i=pre[i])                    delta=min(delta,mp[pre[i]][i]);                for (i=t;i!=s;i=pre[i])                    mp[pre[i]][i]-=delta,mp[i][pre[i]]+=delta;                flow+=delta;            }        }        else        {            int x=reLable(i);       //重新标号            num[x]++;            num[d[i]]--;            if (num[d[i]]==0)        //间隙优化                return flow;            d[i]=x;            if (i!=s)                i=pre[i];        }    }    return flow;}int main(){    int u,v,c;  //弧的起点,终点,容量    while (scanf("%d%d",&n,&m)!=EOF)  //读入顶点个数n和弧数m    {        memset(mp,0,sizeof(mp));        for (int i=0;i<m;i++)        {            scanf("%d%d%d",&u,&v,&c);            mp[u][v]=c;        }        s=0,t=n-1;        init();        printf("%d\n",maxFlow(0,n-1));    }    return 0;}/*6 100 1 80 2 41 3 21 4 22 1 42 3 12 4 43 4 63 5 94 5 7*/


29 0