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;
    }
    
  • 相关阅读:
    okhttp post用json传递参数
    android10获取相册图片
    从一页跳转到另一页返回后刷新
    获取应用图标并转为bitmap适配android10
    上拉更新,下拉刷新
    android 多图片上传
    04号团队-团队任务5:项目总结会
    codeforces987D bfs跑最短路
    layaair 物理
    TypeScript
  • 原文地址:https://www.cnblogs.com/Qing-LKY/p/luoguP3381-solutio.html
Copyright © 2011-2022 走看看