sap 算法

来源:互联网 发布:安卓看美漫的软件 编辑:程序博客网 时间:2024/06/05 15:50

//hdu 1532 ditch

//看了半天sap  研究了多份模板 终于一次性完成 gap 当前弧  零接表(我用的是静态零接表)  几种优化

//个人觉的和dinic 好像啊  交了两上个题目 和我之前写了 有当前弧优化的 dinic时间居然 一样  可能题目数据的原因

 #include<iostream>
#include<cstdio>
#include<queue>
#include<string>
#define INF 0x7fffffff
using namespace std;
const int E = 505;
const int V = 205;
struct Edge{
    int u,v,c;
    int next;
}edg[E];
int head[V],dis[V],gap[V],stack[V],temp[V],neck[V];
int n,m,src,End,e;
inline void addedge(int u,int v,int c)
{
    edg[e].u = u; edg[e].v = v; edg[e].c = c;
    edg[e].next = head[u];
     head[u] = e++;
}
void rev_bfs()
{
    queue<int>q;
    int now,w,c,i,v;
    memset(dis,-1,sizeof(dis));
    memset(gap,0,sizeof(gap));                           //   初始化gap
    dis[End] = 0;
    q.push(End);
    while(!q.empty())
    {
        now = q.front();
        q.pop();
        gap[dis[now]]++;
        for(i = head[now]; i != -1; i = edg[i].next)
        {
            v = edg[i].v;
            c = edg[i^1].c;
            if(dis[v] == -1 && c > 0)
            {
                dis[v] = dis[now] + 1;
                q.push(v);
            }
        }
    }
}                       //反向bfs获得初始标号
int maxflow_sap()
{
    rev_bfs();
    int top,u,i,mink,ret,t,v;
    bool flag;
    memcpy(temp,head,sizeof(temp));                 // 初始化当前弧
    u = src;top = 0;ret = 0;neck[src] = INF;
    while(dis[src] < n)
    {
        if(u == End)                  //找到增广路 增广
        {
            t = INF;mink = 0;
            for(i = 0; i < top; i++)
            {
                v = stack[i];
                if(edg[v].c > 0 && t > edg[v].c)
                {
                    t = edg[v].c;
                    mink = i;
                }
            }
            for(i = 0; i < top; i++)
            {
                v = stack[i];
                edg[v].c -= t;
                edg[v^1].c += t;                     // 反向弧增加
            }
            ret += t;
            top = mink;
            u = edg[stack[top]].u;                        //返回至阻塞流前一个顶点  既源点能够达到的最后一个顶点  减少搜索次数
        }
        for(i = temp[u]; i != -1; i = edg[i].next)
        {
            if(edg[i].c > 0 && dis[edg[i].v] == dis[u] - 1)
            break;
        }
        if(i != -1)                                 //找到允许弧    advance
        {
            stack[top++] = i;
            temp[u] = i;
            u = edg[i].v;
        }
        else
        {
            if(--gap[ dis[u] ] == 0)break;                  //gap优化
            temp[u] = head[u];                                  //初始化重标号的当前弧
            t = n - 1;
            for(i = head[u]; i != -1; i= edg[i].next)
            {
                if(edg[i].c > 0)
                t = min(dis[ edg[i].v ],t);
            }
            gap[ dis[u] = t + 1 ]++;         //重标号并 gap++
            if(u != src && top > 0)
            {
                top--;
                u = edg[stack[top]].u;       //回溯 一个节点 找其他路
            }
        }
    }
    return ret;
}
void Init()
{
    int i,s,t,c;
    memset(head,-1,sizeof(head));
    e = 0;src = 1;End = n;
    for(i = 1; i <= m; i++)
    {
        scanf("%d %d %d",&s,&t,&c);
        addedge(s,t,c);
        addedge(t,s,0);//建为0的反边
    }
    printf("%d/n",maxflow_sap());
}
int main()
{
    while(scanf("%d %d",&m,&n) != EOF)
    {
        Init();
    }
    return 0;
}

原创粉丝点击