(模板题)loj #127. 最大流 加强版(hlpp)

题目链接:https://loj.ac/problem/127

最大流hlpp模板(原作者是xehoth,我就改了改拿来用用)

请根据题目要求做修改。

Note:可将vector改为链式前向星,代码我就不贴出来了,如有需要请私信我。

update(2018.9.29):

算是对这个板子的总结。

在检验板子的时候发现这个东西跑网络流时间下限较高,但上限小,适合跑边数多的图,毕竟O(n^{2}m^{\frac{1}{2}}),时间也很稳定,对于一些随机图而言dinic,isap跑得比它快。

个人认为:

vector存图适用于边多点少,跑的比前向星快。

而前向星适用于边少点多,跑的比vector快。

但只是个人猜测,没有任何证明。

速度对比(hdu 4280):

从上到下依次是:

不带fastio的dinic、不带fastio的hlpp(前向星)、不带fastio的hlpp(vector)、带fastio的dinic、带fastio的hlpp(vector)、带fastio的hlpp(前向星)

可见这东西的速度有多可怕了,但是这个东西应该属于娱乐向,因为现场赛靠谱的出题人出个网络流基本不会卡dinic,否则就是写残了、板子问题、图没建对、这题就不是用网络流做的等等。

示例程序:

/**
 * Copyright (c) 2017-2018, xehoth
 * All rights reserved.
 * 25-01-2018
 * HighestLabelPreflowPush
 *
 * updated 05-02-2018
 * globalRelabel only once
 *
 * updated 03-03-2018
 * fix INF
 * @author xehoth
 */
#include <bits/stdc++.h>
#define INF INT_MAX
using namespace std;
struct node
{
    int v,cap,index;
};
vector<node>edge[1203];
vector<int>List[1203];
vector<list<int>::iterator>listit;
list<int>dlist[1203];
int highest,highestActive,vis[1203],excess[1203],height[1203];
void insert(int u,int v,int cap)
{
    edge[u].push_back(node{v,cap,edge[v].size()});
    edge[v].push_back(node{u,0,edge[u].size()-1});
}
void globalRelabel(int n,int t)
{
    int u,i,hp,v,index;
    queue<int>q;
    for(i=0;n>=i;i++)
    {
        height[i]=n;
    }
    height[t]=0;
    memset(vis,0,sizeof(vis));
    q.push(t);
    while(q.empty()==0)
    {
        u=q.front();
        q.pop();
        for(i=0;edge[u].size()>i; i++)
        {
            v=edge[u][i].v;
            index=edge[u][i].index;
            if(height[v]==n&&edge[v][index].cap>0)
            {
                height[v]=height[u]+1;
                vis[height[v]]++;
                q.push(v);
                hp=v;
            }
        }
    }
    for(i=0;n>=i;i++)
    {
        List[i].clear();
        dlist[i].clear();
    }
    for(i=0;n>i;i++)
    {
        if(height[i]<n)
        {
            listit[i]=dlist[height[i]].insert(dlist[height[i]].begin(),i);
            if(excess[i]>0)
            {
                List[height[i]].push_back(i);
            }
        }
    }
    highest=height[hp];
    highestActive=height[hp];
}
void push(int u,node &e)
{
    int v,df;
    v=e.v;
    df=min(excess[u],e.cap);
    e.cap=e.cap-df;
    edge[v][e.index].cap=edge[v][e.index].cap+df;
    excess[u]=excess[u]-df;
    excess[v]=excess[v]+df;
    if(excess[v]>0&&excess[v]<=df)
    {
        List[height[v]].push_back(v);
    }
}
void discharge(int n,int u)
{
    int i,nh,v,cap,h;
    nh=n;
    for(i=0;edge[u].size()>i;i++)
    {
        v=edge[u][i].v;
        cap=edge[u][i].cap;
        if(cap>0)
        {
            if(height[u]==height[v]+1)
            {
                push(u,edge[u][i]);
                if(excess[u]==0)
                {
                    return;
                }
            }
            else
            {
                nh=min(nh,height[v]+1);
            }
        }
    }
    h=height[u];
    if(vis[h]==1)
    {
        for(i=h;highest>=i;i++)
        {
            for(list<int>::iterator it=dlist[i].begin();it!=dlist[i].end();it++)
            {
                vis[height[*it]]--;
                height[*it]=n;
            }
            dlist[i].clear();
        }
        highest=h-1;
    }
    else
    {
        vis[h]--;
        listit[u]=dlist[h].erase(listit[u]);
        height[u]=nh;
        if(nh==n)
        {
            return;
        }
        vis[nh]++;
        listit[u]=dlist[nh].insert(dlist[nh].begin(),u);
        highestActive=nh;
        highest=max(highest,highestActive);
        List[nh].push_back(u);
    }
}
int hlpp(int n,int s,int e)
{
    int i,u;
    if(s==e)
    {
        return 0;
    }
    highestActive=0;
    highest=0;
    memset(height,0,sizeof(height));
    height[s]=n;
    listit.resize(n);
    for(i=0;n>i;i++)
    {
        if(i!=s)
        {
            listit[i]=dlist[height[i]].insert(dlist[height[i]].begin(),i);
        }
    }
    memset(vis,0,sizeof(vis));
    vis[0]=n-1;
    memset(excess,0,sizeof(excess));
    excess[s]=INF;
    excess[e]=-INF;
    for(i=0;edge[s].size()>i;i++)
    {
        push(s,edge[s][i]);
    }
    globalRelabel(n,e);
    while(highestActive>=0)
    {
        if(List[highestActive].empty()==1)
        {
            highestActive--;
            continue;
        }
        u=List[highestActive].back();
        List[highestActive].pop_back();
        discharge(n,u);
    }
    return excess[e]+INF;
}
int main()
{
    int n, m, s, t;
    scanf("%d %d %d %d",&n,&m,&s,&t);
    for (int i = 0, u, v, f; i < m; i++)
    {
        scanf("%d %d %d",&u,&v,&f);
        insert(u, v, f);
    }
    printf("%d",hlpp(n + 1, s, t));
    return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值