W
e
l
c
o
m
e
: )

网络流模板

保存备用。

Dinic 网络流

/**
   *  @brief Dinic 网络流模板。
   *  @tparam  Tp  权值的类型。
   *  @tparam  sizn  点的数量。
   *  @tparam  sizm  边的数量。
*/
template<typename Tp, size_t sizn, size_t sizm>
struct netflow
{
    int cnt=1, s=sizn-3, t=sizn-2;
    Tp val[sizm<<1], dis[sizn];

    /**
     *  @brief  建一条有一定最大流量的有向边。
     *  @param  u  有向边的起点。
     *  @param  v  有向边的终点。
     *  @param  w  边的最大流量。
    */
    void link(int u, int v, Tp w) 
    {
        to [++cnt]=v;       val [cnt]=w;
        nxt[ cnt ]=head[u]; head[ u ]=cnt;
        to [++cnt]=u;       val [cnt]=0;
        nxt[ cnt ]=head[v]; head[ v ]=cnt;
    }

    const Tp inf=((Tp)INFINITY)>>1;
    private:

    int head[sizn], to[sizm<<1], nxt[sizm<<1], now[sizm<<1];
    // 在残量网络中构造分层图
    int bfs() 
    {
        for(int i=1;i<sizn;i++) dis[i]=inf;
        queue<int> q;
        q.push(s);
        dis[s]=0;
        now[s]=head[s];
        while (!q.empty())
        {
            int idx=q.front(); q.pop();
            for(int i=head[idx];i;i=nxt[i])
            {
                int arr=to[i];
                if(val[i]>0&&dis[arr]==inf)
                {
                    q.push(arr);
                    now[arr]=head[arr];
                    dis[arr]=dis [idx]+1;
                    if(arr==t) return 1;
                }
            }
        }
        return 0;
    }
    
    // dfs 找增广路并处理
    Tp dfs(int idx, Tp sum)
    {
        if(idx==t) return sum;
        Tp k, res=0;
        for(int i=now[idx];i&&sum;i=nxt[i])
        {
            now[idx]=i;
            int arr=to[i];
            if(val[i]>0&&(dis[arr]==dis[idx]+1))
            {
                k=dfs(arr, min(sum, val[i]));
                if(k==0) dis[arr]=inf;
                val[i]-=k;      res+=k;
                val[i^1]+=k;    sum-=k;
            }
        }
        return res;
    }
    public:
    
    /**
     *  @brief  Dinic求解最大流。
     *  @return 最大流大小。
     *  @warning 它不能在常数时间内给出结果。
    */
    Tp maxflow()
    {
        Tp ans=0;
        while (bfs()) ans+=dfs(s, inf); 
        return ans;
    }
};

Primal-Dual 费用流

/**
   * @brief Primal 费用流模板。
   * @tparam  Tp  权值的类型。
   * @tparam  sizn  点的数量。
   * @tparam  sizm  边的数量。
*/
template<typename Tp, size_t sizn, size_t sizm>
struct costflow
{
    #define pb __gnu_pbds
    typedef pb::priority_queue<pair<Tp, int>, 
                               greater<pair<Tp, int> >, 
                               pb::pairing_heap_tag> pairing_heap;

    int cnt=1, s=sizn-2, t=sizn-3;
    Tp delta=0, MXflow=0, MNcost=0;

    /**
     * @brief  建一条有一定最大流量的有向边。
     * @param  u  有向边的起点。
     * @param  v  有向边的终点。
     * @param  w  边的最大流量。
     * @param  f  边的费用。
    */
    void link(int u, int v, Tp w, Tp f) 
    {
        to [++cnt]=v;       cap [cnt]=w;
        nxt[ cnt ]=head[u]; head[ u ]=cnt;
        cost[cnt ]=f;       from[cnt]=u;
        to [++cnt]=u;       cap [cnt]=0;
        nxt[ cnt ]=head[v]; head[ v ]=cnt;
        cost[cnt ]=-f;      from[cnt]=v;
    }

    private:

    bitset<sizn> vis;
    pairing_heap pq; 
    typename pairing_heap :: point_iterator it[sizn];
    Tp val[sizm<<1], dis[sizn], flow[sizn], cost[sizm<<1], cap[sizm<<1];
    int head[sizn], to[sizm<<1], nxt[sizm<<1], now[sizm<<1], from[sizm<<1];

    bool SPFA()
    {
        queue<int> q;
        memset(dis, 0x3f, sizeof dis);
        vis.reset();
        dis[t]=0; q.push(t);
        vis[t]=1;
        while (!q.empty())
        {
            int u=q.front(); q.pop();
            vis[u]=0;
            for(int i=head[u];i;i=nxt[i])
            {
                int v=to[i];
                Tp f=val[i^1], c=cap[i^1], len=cost[i^1];
                if(f<c&&dis[v]>dis[u]+len)
                {
                    dis[v]=dis[u]+len;
                    if(!vis[v]) vis[v]=1, q.push(v);
                }
            }
        }
        return dis[s]!=dis[0];
    }

    void reduce()
    {
        for(int i=2;i<=cnt;i++) cost[i]+=dis[to[i]]-dis[from[i]];
        delta+=dis[s];
    }

    bool Dijkstra() 
    {
        memset(dis, 0x3f, sizeof dis);
        memset(it, 0, sizeof it);
        dis[t] = 0; 
        it[t] = pq.push({dis[t], t});
        while(!pq.empty()) 
        {
            int u = pq.top().second; pq.pop();
            for(int j=head[u];j;j=nxt[j]) 
            {
                int v=to[j];
                Tp f=val[j^1], c=cap[j^1], len=cost[j^1];
                if(f<c&&dis[v]>dis[u]+len) 
                {
                    dis[v]=dis[u]+len;
                    if(it[v]==NULL) it[v]=pq.push({dis[v], v});
                    else pq.modify(it[v], {dis[v], v});
                }
            }
        }
        return dis[s] != dis[0];
    }
    
    // dfs 找增广路并处理
    Tp dfs(int idx, Tp sum)
    {
        if(idx==t) return sum;
        vis[idx]=1;
        Tp k, ret=sum;
        for(int i=head[idx];i&&sum;i=nxt[i])
        {
            int v=to[i];
            Tp f=val[i], c=cap[i], len=cost[i];
            if(!vis[v]&&f<c&&!len)
            {
                k=dfs(v, min(ret, c-f));
                val[i]+=k;
                val[i^1]-=k;    
                ret-=k;
            }
        }
        return sum-ret;
    }

    void augment()
    {
        Tp curflow=0;
        vis.reset();
        while((curflow=dfs(s, dis[0])))
        {
            MXflow+=curflow;
            MNcost+=curflow*delta;
            vis.reset();
        }
    }
    public:
    /**
     *  @brief  Primal Dual 求解最小费用最大流。
     *  @return 无。
     *  @warning 它不能在常数时间内给出结果。
    */
    void PrimalDual()
    {
        if(!SPFA()) return;
        reduce(); augment();
        while(Dijkstra()) {reduce(); augment();}
    }
};

最高标号预流推进


template<typename Tp, size_t sizn, size_t sizm>
struct HLPP
{
    int cnt=1, s=sizn-5, t=sizn-4, n=0;
    Tp val[sizm<<1], dis[sizn];
    int head[sizn], to[sizm<<1], nxt[sizm<<1], now[sizm<<1];

    void link(int u, int v, Tp w) 
    {
        n=max({n, u, v});
        to [++cnt]=v;       val [cnt]=w;
        nxt[ cnt ]=head[u]; head[ u ]=cnt;
        to [++cnt]=u;       val [cnt]=0;
        nxt[ cnt ]=head[v]; head[ v ]=cnt;
    }

    const Tp inf=0x3f3f3f3f;

    int hgt[sizn], gap[sizn], vis[sizn];
    Tp excess[sizn];

    queue<int> q;

    bool init()
    {
        fill_n(hgt, sizn, inf);
        hgt[t]=0;
        q.emplace(t);
        while(!q.empty())
        {
            int u=q.front();
            q.pop();
            for(int i=head[u];i;i=nxt[i])
                if(val[i^1]&&hgt[to[i]]-1>hgt[u])
                    q.emplace(to[i]),
                    hgt[to[i]]=hgt[u]+1;
        }
        return hgt[s]!=inf;
    }

    priority_queue<pair<int, int>> pq;

    void push(int u)
    {
        for(int i=head[u];i;i=nxt[i])
        {
            int v=to[i];
            if(!excess[u]) break;
            if(!val[i]||hgt[v]!=hgt[u]-1) continue;
            Tp flw=min(val[i], excess[u]);
            val[i]-=flw, val[i^1]+=flw;
            excess[u]-=flw;
            excess[v]+=flw;
            if(v!=s&&v!=t&&!vis[v])
                vis[v]=1, pq.emplace(hgt[v], v);
        }
    }

    void relabel(int u)
    {
        hgt[u]=inf;
        for(int i=head[u];i;i=nxt[i])
            if(val[i]&&hgt[to[i]]<hgt[u]-1)
                hgt[u]=hgt[to[i]]+1;
    }

    Tp maxflow()
    {
        if(!init()) return 0;
        hgt[s]=n;
        for(int i=1;i<=n;i++)
            if(hgt[i]!=inf) gap[hgt[i]]++;
        for(int i=head[s];i;i=nxt[i])
        {
            int v=to[i];
            if(!val[i]||hgt[v]==inf) continue;
            Tp flw=val[i];
            val[i]-=flw, val[i^1]+=flw;
            excess[s]-=flw, excess[v]+=flw;
            if(v!=s&&v!=t&&!vis[v])
                vis[v]=1, pq.emplace(hgt[v], v);
        }
        while(!pq.empty())
        {
            int u=pq.top().second;
            pq.pop();
            vis[u]=0;
            push(u);
            if(!excess[u]) continue;
            if(!--gap[hgt[u]])
                for(int i=1;i<=n;i++)
                if(i!=s&&i!=t&&hgt[i]>hgt[u]&&hgt[i]<n+1)
                    hgt[i]=n+1;
            relabel(u);
            ++gap[hgt[u]];
            vis[u]=1;
            pq.emplace(hgt[u], u);
        }
        return excess[t];
    }
};
posted @ 2024-03-10 22:04  Jimmy-LEEE  阅读(42)  评论(0)    收藏  举报