zoukankan      html  css  js  c++  java
  • 【luogu P3381】最小费用最大流 题解

    原题链接

    由于题解已经烂大街了,这里只列出注意事项和部分个人难以理解的内容。

    注意事项

    1. 边下标从2开始
    2. 区分流量和单价
    3. 使用dijkstra最好开long long 小心h[x]爆掉

    h[x]+=dis[x]的正确性证明

    代码库

    SPFA

    #include <cstdio>
    #include <queue>
    #include <algorithm>
    #define REG register
    #define rep(i,a,b) for(REG int i=a;i<=b;i++)
    #define Rep(i,a,b) for(REG int i=a;i>=b;i--)
    inline char getc(){
        static char buf[1<<14],*p1=buf,*p2=buf;
        return p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<14,stdin),p1==p2)?EOF:*p1++;
    }
    inline int scan(){
        REG int x=0; REG char ch=0;
        while(ch<48) ch=getc();
        while(ch>=48) x=x*10+ch-48,ch=getc();
        return x;
    }
    const int N=5e3+5,M=5e4+5,INF=2147483647;
    int n,m,s,t,head[N],nex[M<<1],to[M<<1],wei[M<<1],cost[M<<1];
    inline void addEdge(int u,int v,int w,int c){
        static int cc=1; //差点又忘了
        nex[++cc]=head[u]; head[u]=cc; 
        to[cc]=v; wei[cc]=w; cost[cc]=c;
    }
    int h[N],dis[N],pre[N],prE[N]; 
    bool vis[N]; std::queue<int> Q; 
    inline bool SPFA(){
        //static int err=0;
        //err++; if(err>10) return 0;
        rep(i,1,n) dis[i]=INF,vis[i]=pre[i]=prE[i]=0;
        Q.push(s); dis[s]=0; vis[s]=1;
        //printf("order:
    ");
        while(!Q.empty()){
            REG int u=Q.front(); Q.pop(); vis[u]=0;
            if(u==t) continue; 
            //到t就行了 注意这里不能break 因为只是搜到了t不代表dis[t]已经最小
            for(REG int i=head[u];i;i=nex[i]){
                if(!wei[i]) continue;
                //printf("%d->%d %d cmp %d
    ",u,to[i],dis[u]+cost[i],dis[to[i]]);
                //一条增广路的流量是相同的 所以求出的单位价格之和最小即可
                if(dis[u]+cost[i]<dis[to[i]]){
                    dis[to[i]]=dis[u]+cost[i];
                    pre[to[i]]=u; prE[to[i]]=i;
                    if(!vis[to[i]]) vis[to[i]]=1,Q.push(to[i]);
                }
            }
        }
        //putchar('
    ');
        return pre[t];
    }
    int Mflow,Mcost;
    inline void calc(){
        REG int u,flow;
        for(u=t,flow=INF;pre[u];u=pre[u]) flow=std::min(flow,wei[prE[u]]);
        Mflow+=flow; Mcost+=dis[t]*flow;
        for(u=t;pre[u];u=pre[u]) wei[prE[u]]-=flow,wei[prE[u]^1]+=flow;
        //printf("ss
    ");
    }
    int main(){
        //freopen("P3381_8.in","r",stdin);
        n=scan(),m=scan(),s=scan(),t=scan();
        REG int u,v,w,c;
        while(m--){
            u=scan(),v=scan(),w=scan(),c=scan();
            addEdge(u,v,w,c); addEdge(v,u,0,-c);
        }
        while(SPFA()) calc();
        printf("%d %d
    ",Mflow,Mcost);
        return 0;
    }
    

    dijkstra

    #include <cstdio>
    typedef long long ll;
    #define REG register
    #define rep(i,a,b) for(REG int i=a;i<=b;i++)
    #define Rep(i,a,b) for(REG int i=a;i>=b;i--)
    inline char getc(){
        static char buf[1<<14],*p1=buf,*p2=buf;
        return p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<14,stdin),p1==p2)?EOF:*p1++;
    }
    inline int scan(){
        REG int x=0; REG char ch=0;
        while(ch<48) ch=getc();
        while(ch>=48) x=x*10+ch-48,ch=getc();
        return x;
    }
    inline ll min(const ll&a,const ll&b){ return a<b?a:b; }
    template<typename T> inline void swap(T &a,T &b){ REG T t=a; a=b; b=t; }
    const int N=5e3+5,M=5e4+5; const ll INF=1e18;
    struct Heap{
        struct node{
            int i,siz; ll d; node *ch[2];
            node(int a=0,ll b=0):i(a),d(b),siz(1){ ch[0]=ch[1]=NULL; }
            inline void maintain(){
                siz=1; 
                if(ch[0]) siz+=ch[0]->siz;
                if(ch[1]) siz+=ch[1]->siz;
            } 
        }*root;
        inline void get_top(int &a,ll &b){ a=root->i; b=root->d; }
        inline int _siz(const node *u){ return u?u->siz:0; }
        inline ll _dis(const node *u){ return u?u->d:INF; }
        inline void _insert(node*&u,int i,ll d){
            if(!u) u=new node(i,d);
            else{
                if(u->d>d) swap(u->d,d),swap(u->i,i);
                REG int judge=_siz(u->ch[0])-_siz(u->ch[1]);
                _insert(u->ch[judge>0?1:0],i,d); 
                u->maintain();
            }
        }
        inline void _delete(node*&u){
            if(u->ch[0]||u->ch[1]){
                REG int j=_dis(u->ch[0])-_dis(u->ch[1])>0?1:0;
                swap(u->d,u->ch[j]->d); swap(u->i,u->ch[j]->i);
                _delete(u->ch[j]); u->maintain();
            }else{ delete u; u=NULL; }
        }
    }Q;
    int n,s,t,head[N],nex[M<<1],to[M<<1]; ll wei[M<<1],cost[M<<1];
    inline void addEdge(int u,int v,int w,int c){
        static int cc=1; 
        nex[++cc]=head[u]; head[u]=cc;
        to[cc]=v; wei[cc]=w; cost[cc]=c;
    } 
    ll h[N],dis[N],Mcost,Mflow; int pre[N],preE[N]; bool vis[N];
    inline bool dijkstra(){
        //static int cnt=0;
        //if((++cnt)&&Mflow>2938) return printf("%d
    ",cnt),0;
        rep(i,1,n) dis[i]=INF,pre[i]=preE[i]=vis[i]=0;
        Q._insert(Q.root,s,0); dis[s]=0;
        while(Q.root){
            REG int u; REG ll d; 
            Q.get_top(u,d); Q._delete(Q.root);
            if(d>dis[u]||vis[u]||u==t) continue;
            vis[u]=1; 
            for(REG int i=head[u];i;i=nex[i]){
                if(!wei[i]||vis[to[i]]) continue;
                REG ll eff=cost[i]+h[u]-h[to[i]];
                if(dis[u]+eff<dis[to[i]]){
                    dis[to[i]]=dis[u]+eff;
                    pre[to[i]]=u; preE[to[i]]=i;
                    Q._insert(Q.root,to[i],dis[to[i]]);
                }
            }
        }
        return pre[t];
    }
    inline void calc(){
        REG ll per_cost=dis[t]-h[s]+h[t],flow=INF;
        //注意这里的wei[...]
        for(REG int i=t;pre[i];i=pre[i]) flow=min(flow,wei[preE[i]]);
        Mflow+=flow; Mcost+=flow*per_cost;
        for(REG int i=t;pre[i];i=pre[i]) wei[preE[i]]-=flow,wei[preE[i]^1]+=flow;
        rep(i,1,n) h[i]+=dis[i];
    }
    int main(){
        //freopen("P3381_8.in","r",stdin);
        REG int m,u,v,w,c;
        n=scan(),m=scan(),s=scan(),t=scan(); 
        while(m--){
            u=scan(),v=scan(),w=scan(),c=scan();
            addEdge(u,v,w,c); addEdge(v,u,0,-c);
        }
        //printf("ss");
        while(dijkstra()) calc();
        printf("%lld %lld
    ",Mflow,Mcost);
        return 0;
    }
    
  • 相关阅读:
    Max Sum Plus Plus HDU
    Monkey and Banana HDU
    Ignatius and the Princess IV HDU
    Extended Traffic LightOJ
    Tram POJ
    Common Subsequence HDU
    最大连续子序列 HDU
    Max Sum HDU
    畅通工程再续
    River Hopscotch POJ
  • 原文地址:https://www.cnblogs.com/Qing-LKY/p/luoguP3381-solutio.html
Copyright © 2011-2022 走看看