网络流之预流推进

emmmm LOJ这个最大流加强版卡掉了我心爱的Dinic板子
加强版最大流
在这里插入图片描述
这这这也太丝滑了吧 LOJ板子题跑了400ms

#pragma GCC optimize("Ofast,unroll-loops")
#pragma GCC target("avx")
#include <bits/stdc++.h>
using namespace std;

int getint() {
    char c;
    while (not isdigit(c = getchar()))
        ;
    int res = c - '0';
    while (isdigit(c = getchar())) res = res * 10 + (c - '0');
    return res;
}

template <class T>
struct push_relabel {
    struct arc {
        int to, rev;
        T cap;
    };
    const T inf = numeric_limits<T>::max();
    const int n;
    vector<tuple<int, int, T, T>> arc_pool;
    vector<arc> g;
    vector<int> head, ptr, d;
    vector<T> ex;
    vector<vector<int>> active;
    vector<set<int>> vs;
    int highest, works;
    push_relabel(int _n) : n(_n), head(n + 1), ptr(n), d(n), ex(n), active(n), vs(n) {}
    void add(int from, int to, T cap, bool directed = true) {
        assert(cap >= 0);
        if (from == to or cap == 0)
            return;
        arc_pool.emplace_back(from, to, cap, directed ? 0 : cap);
        ++head[from], ++head[to];
    }
    void build() {
        for (int v = 0; v < n; ++v) head[v + 1] += head[v];
        g.resize(head[n]);
        for (auto&& e : arc_pool) {
            int i = --head[get<0>(e)], j = --head[get<1>(e)];
            g[i] = { get<1>(e), j, get<2>(e) }, g[j] = { get<0>(e), i, get<3>(e) };
        }
    }
    void push(int v, arc& a) {
        if (ex[a.to] == 0)
            active[d[a.to]].push_back(a.to);
        T delta = min(ex[v], a.cap);
        ex[v] -= delta, ex[a.to] += delta;
        a.cap -= delta, g[a.rev].cap += delta;
    }
    void relabel(int v) {
        ++works;
        int mn = 2 * n;
        for (int i = head[v]; i < head[v + 1]; ++i)
            if (g[i].cap)
                mn = min(mn, d[g[i].to]);
        if (vs[d[v]].size() == 1) {
            for (int i = d[v]; i < n; ++i) {
                for (int u : vs[i]) d[u] = n;
                active[i].clear(), vs[i].clear();
            }
            return;
        }
        vs[d[v]].erase(v);
        if ((d[v] = mn + 1) < n)
            vs[highest = d[v]].insert(v);
    }
    void discharge(int v) {
        int i = ptr[v];
        while (ex[v]) {
            if (i == head[v + 1]) {
                relabel(v), i = head[v];
                if (d[v] >= n)
                    break;
            } else {
                if (g[i].cap and d[v] > d[g[i].to])
                    push(v, g[i]);
                else
                    ++i;
            }
        }
        ptr[v] = i;
    }
    void global_relabel(int t) {
        copy(begin(head), begin(head) + n, begin(ptr));
        fill(begin(d), end(d), n);
        for (int i = 0; i < n; ++i) active[i].clear(), vs[i].clear();
        highest = -1, works = 0;
        queue<int> que;
        d[t] = 0, que.push(t);
        while (not que.empty()) {
            int v = que.front();
            que.pop();
            vs[d[v]].insert(v);
            for (int i = head[v]; i < head[v + 1]; ++i)
                if (g[g[i].rev].cap and d[g[i].to] == n) {
                    d[g[i].to] = d[v] + 1, que.push(g[i].to);
                    if (ex[g[i].to])
                        active[highest = d[g[i].to]].push_back(g[i].to);
                }
        }
    }
    T max_flow(int s, int t) {
        build();
        ex[s] = inf, ex[t] = -inf;
        for (int i = head[s]; i < head[s + 1]; ++i) push(s, g[i]);
        global_relabel(t);
        for (; highest >= 0; --highest)
            while (not active[highest].empty()) {
                int v = active[highest].back();
                active[highest].pop_back();
                discharge(v);
                if (works > 4 * n)
                    global_relabel(t);
            }
        return inf + ex[t];
    }
};

struct stopwatch {
    clock_t t = clock();
    void restart() { t = clock(); }
    int elapsed() const { return (clock() - t) * 1000 / CLOCKS_PER_SEC; }
    friend string to_string(stopwatch sw) { return "Time: " + to_string(sw.elapsed()) + " ms"; }
} sw;

int main() {
    int n = getint(), m = getint(), s = getint() - 1, t = getint() - 1;
    push_relabel<int> g(n);
    while (m--) {
        int u = getint() - 1, v = getint() - 1, c = getint();
        g.add(u, v, c);
    }
    cout << g.max_flow(s, t) << '\n';
}

再来看看这份 7K多ms

#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
#include<queue>
#include<vector>
using namespace std;
inline int Read(){
    int x=0;
    char c=getchar();
    while(c>'9'||c<'0')c=getchar();
    while(c>='0'&&c<='9')x=x*10+c-'0',c=getchar();
    return x;
}
const int inf=1<<30;
int top=1,head[10100];
int n,m,s,t;
int e[10100],h[10100],cnth[20100];//每个点对应的余流,高度;每个高度有多少个点
struct cmp{
    inline bool operator () (int a,int b) const{
        return h[a]<h[b];
    }
};
struct Node{
    int v;
    int val;
    int next;
}node[400100];
inline void addedge(int u,int v,int val){
    node[++top].v=v;
    node[top].val=val;
    node[top].next=head[u];
    head[u]=top;
}
inline void add(int u,int v,int val){
    addedge(u,v,val);
    addedge(v,u,0);
}
int inque[11000];
void bfs(){
    memset(h,0x3f,sizeof(h));
    h[t]=0;
    queue<int>qu;
    qu.push(t);
    while(!qu.empty()){
        int u=qu.front();
        qu.pop();
        inque[u]=0;
        for(int i=head[u];i;i=node[i].next){
            int d=node[i].v;
            if(node[i^1].val&&h[d]>h[u]+1){//反向跑
                h[d]=h[u]+1;
                if(inque[d]==0){
                    qu.push(d);
                    inque[d]=1;
                }
            }
        }
    }
    return;
}
priority_queue<int,vector<int>,cmp>q;
inline void push_(int u){
    for(int i=head[u];i;i=node[i].next){
        int d=node[i].v;
        if(node[i].val&&h[d]+1==h[u]){//可以推流
            int mi=min(node[i].val,e[u]);
            node[i].val-=mi;
            node[i^1].val+=mi;
            e[u]-=mi;
            e[d]+=mi;
            if(inque[d]==0&&d!=t&&d!=s){
                q.push(d);
                inque[d]=1;
            }
            if(e[u]==0)break;//已经推完了
        }
    }
}//推流
inline void relabel(int u){
    h[u]=inf;
    for(int i=head[u];i;i=node[i].next){
        int d=node[i].v;
        if(node[i].val&&h[d]+1<h[u]){
            h[u]=h[d]+1;
        }
    }
}//把u的高度更改为与u相邻的最低的点的高度加1
int hlpp(){
    register int i;
    bfs();
    if(h[s]==0x3f3f3f3f)return 0;//s与t不连通
    h[s]=n;
    for(i=1;i<=n;i++)if(h[i]<0x3f3f3f3f)cnth[h[i]]++;//统计各个高度的点数,注意不要让下标越界
    for(i=head[s];i;i=node[i].next){
        int d=node[i].v;
        int mi=node[i].val;
        if(mi){
            e[s]-=mi;
            e[d]+=mi;
            node[i].val-=mi;
            node[i^1].val+=mi;
            if(d!=t&&inque[d]==0&&d!=s){
            q.push(d);
            inque[d]=1;
            }
        }
    }//从s向周围点推流
    while(!q.empty()){
        int u=q.top();
        inque[u]=0;
        q.pop();
        push_(u);
        if(e[u]){//还有余流
            cnth[h[u]]--;
            if(cnth[h[u]]==0){
                for(int i=1;i<=n;i++){
                    if(i!=s&&i!=t&&h[i]>h[u]&&h[i]<n+1){
                        h[i]=n+1;//标记无法到达
                    }
                }
            }//gap优化
            relabel(u);
            cnth[h[u]]++;
            q.push(u);
            inque[u]=1;
        }
    }
    return e[t];
}
int main(){
    n=Read(),m=Read(),s=Read(),t=Read();
    register int i;
    int u,v,val;
    for(i=1;i<=m;i++)u=Read(),v=Read(),val=Read(),add(u,v,val);
    printf("%d",hlpp());
    return 0;
}

先来一个懵逼费用流 (无脑TLE)
费用流||KM都可以
第一发交了个暴力建图,TLE了,重新读题发现有重边,后来考虑过的都想进去了,还是无脑TLE = 。= 好像是数组开小了的锅 (HDU真莫名其妙 )

#include <bits/stdc++.h>
#include <stdlib.h>
#include <algorithm>
#include <stdio.h>
#include <string.h>
#include<queue>
#include <time.h>
#include <cstdio>
#include <iostream>
#include <vector>
#define ll int
//#define int long long
//#define inf 0x3f3f3f3f
#define mods 1000000007
#define modd 998244353
#define PI acos(-1)
#define fi first
#define se second
#define lowbit(x) (x & (-x))
#define mp make_pair
#define pb push_back
#define si size()
#define E exp(1.0)
#define fixed cout.setf(ios::fixed)
#define fixeds(x) setprecision(x)
#define Re register int
using namespace std;
const int N=10000,M=1e6+3,inf=1e9;
int x,y,z,w,o=1,n,m,h,t,st,ed,cyf[N],pan[N],pre[N],dis[N],head[N];
ll mincost,maxflow;
ll hnr;
ll xfz;
struct QAQ{int w,to,next,flow;}a[M<<1];
queue<int>Q;
inline void read(Re &x){
    int f=0;x=0;char c=getchar();
    while(c<'0'||c>'9')f|=c=='-',c=getchar();
    while(c>='0'&&c<='9')x=(x<<1)+(x<<3)+(c^48),c=getchar();
    x=f?-x:x;
}
inline void add(Re x,Re y,Re z,Re w){a[++o].flow=z,a[o].w=w,a[o].to=y,a[o].next=head[x],head[x]=o;}
inline void add_(Re a,Re b,Re flow,Re w){add(a,b,flow,w),add(b,a,0,-w);}
inline int SPFA(Re st,Re ed){
    for(Re i=0;i<=2*n+1;++i)dis[i]=inf,pan[i]=0;  //有多少个点就初始化到那个地方去
    Q.push(st),pan[st]=1,dis[st]=0,cyf[st]=inf;
    while(!Q.empty()){
    	Re x=Q.front();Q.pop();pan[x]=0;
    	for(Re i=head[x],to;i;i=a[i].next)
            if(a[i].flow&&dis[to=a[i].to]>dis[x]+a[i].w){
                dis[to]=dis[x]+a[i].w,pre[to]=i;
                cyf[to]=min(cyf[x],a[i].flow);
                if(!pan[to])pan[to]=1,Q.push(to);
            }
    }
    return dis[ed]!=inf;
}
inline void EK(Re st,Re ed){
    while(SPFA(st,ed)){
    	Re x=ed;maxflow+=cyf[ed],mincost+=(ll)cyf[ed]*dis[ed];
    	while(x!=st){//和最大流一样的更新
            Re i=pre[x];
            a[i].flow-=cyf[ed];
            a[i^1].flow+=cyf[ed];
            x=a[i^1].to;
    	}
    }
}
ll e[300][300];
void cle(){
o=1;
maxflow=0;
mincost=0;
for(int i=0;i<=5000;i++){
    head[i]=0;
}
}
signed main(){
ll t;
read(t);
while(t--){
 read(n);
 read(m);
 cle();
 for(int i=1;i<=n;i++){
    add_(0,i,1,0);
    add_(i+n,2*n+1,1,0);
    for(int j=1;j<=n;j++){
        e[i][j]=inf;
    }
 }
 for(int i=1;i<=m;i++){
    ll u,v,w;
    read(u);
    read(v);
    read(w);

        e[u][v]=min(e[u][v],w);

    //add_(u,v+n,1,w);
 }
 for(int i=1;i<=n;i++){
    for(int j=1;j<=n;j++){
  //  if(j==i){continue;}
    if(e[i][j]<inf){
     add_(i,j+n,1,e[i][j]);
      // add_(j+n,i,1,e[i][j]);
    }
    }
 }
st=0;
ed=2*n+1;
EK(st,ed);
printf("%d\n",mincost);

}
return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值