1. 程式人生 > >hdu1532最大流EK與SAP演算法

hdu1532最大流EK與SAP演算法

EK是最樸素的最大流演算法了,但效率比較慢,當然程式碼也比較清晰,思路去看LRJ的白書就行了。

但是由於網上大牛總結SAP基本上是解決最大流的最標準模板了,

 網上大牛說基本沒有什麼最大流能卡SAP。

EK程式碼:

#include<iostream>
#include<cstring>
#include<cstdio>
using namespace std;
const int N = 210;   //小規模   不用考慮效率
#define INF  1<<20
int f[N][N];int r[N][N];int c[N][N];
int a[N];int q[N];int p[N];
int main()
{
    int sum,s,n,m,b,t,x,v,k;
    while(scanf("%d%d",&n,&m)!=EOF)
    {
        memset(c,0,sizeof(c));
        memset(f,0,sizeof(f));
        for(int i=0;i<n;i++)
        {
            scanf("%d%d%d",&x,&b,&t);
            c[x][b]+=t;            //注意該題有重邊
        }
        sum=0;

        while(1)
        {
            s=1; int top=0;int last=0;
            memset(p,0,sizeof(p));
            memset(a,0,sizeof(a));
            memset(q,0,sizeof(q));
            a[s]=INF;
            q[top++]=s;
            while(top>last)
            {
                int u=q[last++];
                for(int v=1;v<=m;v++)
                {
                    if(!a[v]&&c[u][v]>f[u][v])
                    {
                        p[v]=u;q[top++]=v;             //記錄v的父親,加入佇列
                        a[v]=a[u]<c[u][v]-f[u][v]?a[u]:c[u][v]-f[u][v];        //最小殘量
                    }
                }
            }
            if(!a[m])  break;    //若沒有更新  說明已經不存在增廣路
                for(k=m;k!=s;k=p[k])
                {
                    f[p[k]][k]+=a[m];
                    f[k][p[k]]+=a[m];
                }
                sum+=a[m];
        }
        printf("%d\n",sum);
    }
    return 0;
}

SAP模板:

#include<cstdio>
#include<cstring>
using namespace std;

const int maxn = 220;
const int inf = 10000000;//不要開太大
int c[maxn][maxn];
int q[maxn], pre[maxn];
int level[maxn], gap[maxn];
int n, m;
int s, t;
void init_sap(){
    memset(level,  1, sizeof (level));
    //printf("---    %d\n", level[2]);
    //for(int i = 0; i <= n; i ++) level[i] =  n + 310;
    memset(gap, 0, sizeof gap);
    memset(pre, -1, sizeof pre);
    int qs = 0, qe = 0;
    q[qe++] = t;
    level[t] = 0;
    gap[ level[t] ] ++;
    while(qs < qe){
        int hd = q[qs++];
        for(int i = 1; i <= n; i ++){
            if(level[i] > n && c[i][hd] > 0){//level[i] >= n  也可以,why ?
                q[qe++] = i;
                level[i] = level[hd] + 1;
                gap[ level[i] ] ++;
            }
        }
    }
}
int find_path(int u){
    for(int i = 1; i <= n; i ++)
      if(c[u][i] > 0 && level[u] == level[i] + 1) return i;
    return -1;
}
int relabel(int u){
    int tmp = inf;
    for(int i = 1; i <= n; i ++)
      if(c[u][i] > 0 && tmp > level[i] + 1)
        tmp = level[i] + 1;
    if(tmp == inf) tmp = n;
    return tmp;
}
int sap(){
    init_sap();
    int flow = 0, u = s;
    while(level[s] <= n){
        int v = find_path(u);
        if(v > 0){
            pre[v] = u;
            u = v;
            if(u == t){
                int min_flow = inf;
                for(int i = t; i != s; i = pre[i])
                  if(min_flow > c[ pre[i]][i])
                    min_flow = c[ pre[i]][i];
                for(int i = t; i != s; i = pre[i]){
                    c[pre[i]][i] -= min_flow;
                    c[i][pre[i]] += min_flow;
                }
                flow += min_flow;
                u = s;
            }
        }else{
            if(-- gap[ level[u]] == 0) return flow;
            int v = relabel(u);
            gap[v] ++;
            level[u] = v;
            if(u != s) u = pre[u];
        }
    }
    return flow;
}
int main(){
    while(~scanf("%d%d", &m, &n)){
        memset(c, 0, sizeof c);
        for(int i = 1; i <= m; i ++){
            int u, v, w;
            scanf("%d%d%d", &u, &v, &w);
            c[u][v] += w;
        }
        s = 1, t = n;
        int flow = sap();
        printf("%d\n", flow);
    }
    return 0;
}