• 学习了ZKW费用流


    所谓ZKW费用流,其实就是Dinic。

    若干年前有一个人发明了最小增广路算法,每次用BFS找一条增广路,时间O(nm^2)

    然后被DinicD飞了:我们为什么不可以在长度不变时多路增广呢?时间O(n^2m)

    #include<cstdio>
    #include<cctype>
    #include<queue>
    #include<cstring>
    #include<algorithm>
    #define rep(s,t) for(int i=s;i<=t;i++)
    #define ren for(int i=first[x];i!=-1;i=next[i])
    using namespace std;
    inline int read() {
        int x=0,f=1;char c=getchar();
        for(;!isdigit(c);c=getchar()) if(c=='-') f=-1;
        for(;isdigit(c);c=getchar()) x=x*10+c-'0';
        return x*f;
    }
    const int inf=1e9;
    const int maxn=100010;
    const int maxm=2000010;
    struct Dinic {
        int n,m,s,t;
        int d[maxn],vis[maxn],first[maxn],cur[maxn],next[maxm];
        struct Edge {int from,to,flow;}edges[maxm];
        Dinic() {
            m=0;
            memset(first,-1,sizeof(first));
        }
        void AddEdge(int from,int to,int cap) {
            edges[m]=(Edge){from,to,cap};next[m]=first[from];first[from]=m++;
            edges[m]=(Edge){to,from,0};next[m]=first[to];first[to]=m++;
        }
        int BFS() {
            memset(vis,0,sizeof(vis));
            queue<int> Q;Q.push(s);d[s]=0;vis[s]=1;
            while(!Q.empty()) {
                int x=Q.front();Q.pop();cur[x]=first[x];
                ren {
                    Edge& e=edges[i];
                    if(e.flow&&!vis[e.to]) vis[e.to]=1,d[e.to]=d[x]+1,Q.push(e.to);
                }
            }
            return vis[t];
        }
        int DFS(int x,int a) {
            if(x==t||!a) return a;
            int flow=0,f;
            for(int& i=cur[x];i!=-1;i=next[i]) {
                Edge& e=edges[i];
                if(d[e.to]==d[x]+1&&(f=DFS(e.to,min(e.flow,a)))) {
                    e.flow-=f;edges[i^1].flow+=f;
                    a-=f;flow+=f;if(!a) break;
                }
            }
            return flow;
        }
        int solve(int s,int t) {
            this->s=s;this->t=t;int ans=0;
            while(BFS()) ans+=DFS(s,inf);
            return ans;
        }
    }sol;
    int main() {
        int n=read(),m=read();
        rep(1,m) {
            int a=read(),b=read(),c=read();
            sol.AddEdge(a,b,c);
        }
        printf("%d
    ",sol.solve(1,n));
        return 0;
    }
    View Code

    于是可以用到费用流里来:我们为什么不可以在s到t最短路不变时多路增广呢?

    实现做法要从t逆向做SPFA,然后多路增广,具体可以见代码

    #include<cstdio>
    #include<cctype>
    #include<queue>
    #include<cstring>
    #include<algorithm>
    #define rep(s,t) for(int i=s;i<=t;i++)
    #define ren for(int i=first[x];i!=-1;i=next[i])
    using namespace std;
    inline int read() {
        int x=0,f=1;char c=getchar();
        for(;!isdigit(c);c=getchar()) if(c=='-') f=-1;
        for(;isdigit(c);c=getchar()) x=x*10+c-'0';
        return x*f;
    }
    const int inf=1e9;
    const int maxn=310;
    const int maxm=300010;
    struct ZKW {
        int n,m,s,t,cost,ans;
        int d[maxn],vis[maxn],first[maxn],inq[maxn],next[maxm];
        struct Edge {int from,to,flow,cost;}edges[maxm];
        void init(int n) {
            this->n=n;m=0;
            memset(first,-1,sizeof(first));
            memset(inq,0,sizeof(inq));
        }
        void AddEdge(int from,int to,int cap,int cost) {
            edges[m]=(Edge){from,to,cap,cost};next[m]=first[from];first[from]=m++;
            edges[m]=(Edge){to,from,0,-cost};next[m]=first[to];first[to]=m++;
        }
        int BFS() {
            rep(1,n) d[i]=inf;
            queue<int> Q;Q.push(t);d[t]=0;
            while(!Q.empty()) {
                int x=Q.front();Q.pop();inq[x]=0;
                ren {
                    Edge& e=edges[i^1];
                    if(e.flow&&d[e.from]>d[x]+e.cost) {
                        d[e.from]=d[x]+e.cost;
                        if(!inq[e.from]) inq[e.from]=1,Q.push(e.from);
                    }
                }
            }
            rep(0,m) edges[i].cost+=d[edges[i].to]-d[edges[i].from];
            cost+=d[s];return d[s]!=inf;
        }
        int DFS(int x,int a) {
            if(x==t||!a) {ans+=cost*a;return a;}
            int flow=0,f;vis[x]=1;
            ren {
                Edge& e=edges[i];
                if(e.flow&&!e.cost&&!vis[e.to]&&(f=DFS(e.to,min(e.flow,a)))) {
                    e.flow-=f;edges[i^1].flow+=f;
                    a-=f;flow+=f;if(!a) break;
                }
            }
            return flow;
        }
        int solve(int s,int t) {
            this->s=s;this->t=t;ans=cost=0;
            while(BFS()) do memset(vis,0,sizeof(vis));while(DFS(s,inf));
            return ans;
        }
    }sol;
    int main() {
        int n=read(),m=read();sol.init(n);
        rep(1,m) {
            int a=read(),b=read(),c=read(),d=read();
            sol.AddEdge(a,b,c,d);
        }
        printf("%d
    ",sol.solve(1,n));
        return 0;
    }
    View Code
  • 相关阅读:
    Android游戏开发实践(1)之NDK与JNI开发02
    SDK接入(1)之Android Facebook SDK接入
    Markdown学习
    SDK接入(3)之iOS内支付(InApp Purchase)接入
    将列【1,2,3】转换为【类别1,类别2,类别3】
    SQL Server 获取日期
    SQL Server 2000 Split方法
    java连接SqlServer2012
    前辈的js学习方法
    js学习笔记
  • 原文地址:https://www.cnblogs.com/wzj-is-a-juruo/p/4593189.html
Copyright © 2020-2023  润新知