• 题解 Luogu P3381 【【模板】最小费用最大流】


    发了网络流,再来一发费用流

    能做费用流的,网络流自然做得来,但在这还是不要脸的安利一下自己的博客(里面也有网络流的题解):

    点我

    扯远了...

    费用流,就是在不炸水管的情况下求源点到汇点的最小费用。

    有没有想起什么?

    思考一下......

    对,最短路径!

    所以我们完全可以用已死的SPFA求出不炸水管的最短路径(当然,实在有心理阴影的可以用dijkstra)。

    如果你最短路径都不会,还是去 这儿 和 这儿

    然后再一把增广路求出最大流与最小费用就好了(我觉得很OK)

    献上本蒟蒻的代码:

    #include<cstdio>
    #define maxn 5050
    #define maxm 50005
    #define INF 0x3f3f3f3f
    inline int read(){
        int r=0,f=1;
        char c=getchar();
        while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
        while(c>='0'&&c<='9'){r=(r<<3)+(r<<1)+c-'0';c=getchar();}
        return r*f;
    }
    int s,t,n,m,head[maxn],pre[maxn],dis[maxn],q[maxn];
    bool vis[maxn];
    int s_e;
    struct E{
        int v,c,w,nxt;
    }e[maxm*2];
    struct Max_fei{//本人喜欢结构体
        inline void a_e(int u,int v,int c,int w){
            e[s_e]=(E){v,c,w,head[u]};
            head[u]=s_e++;
        }
        inline void add(int u,int v,int c,int w){
            a_e(u,v,c,w);
            a_e(v,u,0,-w);
        }
        inline bool spfa(){
            for(int i=1;i<=n;i++){
                dis[i]=INF;
                vis[i]=false;
            }
            dis[s]=0;
            vis[s]=true;
            q[0]=s;
            int hd=0,tl=1;
            while(hd^tl){
                int u=q[hd++];//循环队列
                hd%=maxn;
                for(int i=head[u];i!=-1;i=e[i].nxt){
                    int v=e[i].v;
                    if(dis[v]>dis[u]+e[i].w&&e[i].c){//判断水管还能运水吗
                        dis[v]=dis[u]+e[i].w;//更新
                        pre[v]=i;//记录位置
                        if(vis[v])continue;//如果在队里,那就不进队
                        vis[v]=true;
                        q[tl++]=v;
                        tl%=maxn;
                    }
                }
                vis[u]=false;
            }
            if(dis[t]==INF)return false;
            return true;
        }
        inline int min(int a,int b){//原谅我的手写min
            return a<b?a:b;
        }
        inline int end(int &flow){//flow求最大流
            int p,u,Min=1e9,ans=0;
            for(u=t;u!=s;u=e[p^1].v){//因为开始值为0,可以用xor来找反边
                p=pre[u];//往前找
                Min=min(Min,e[p].c);//找全部经过水管都能流过的最大流
                
            }
            for(u=t;u!=s;u=e[p^1].v){
                p=pre[u];
                e[p].c-=Min;
                e[p^1].c+=Min;
                ans+=e[p].w*Min;//加费用
            }
            flow+=Min;//加最大流
            return ans;
        }
        inline int solve(int &flow){
            int ans=0;
            while(spfa()){
                ans+=end(flow);
            }
            return ans;
        }
    }Flow;
    inline void work(){
        n=read();m=read();
        s=read();t=read();
        for(int i=1;i<=n;i++)head[i]=-1;//初始值为-1,方便xor
        for(int i=1;i<=m;i++){
            int u=read(),v=read(),c=read(),w=read();
            Flow.add(u,v,c,w);
        }
        int flow=0;
        int ans=Flow.solve(flow);
        printf("%d %d\n",flow,ans);
    }
    int main(){
        work();
        return 0;
    }
  • 相关阅读:
    老男孩九期全栈Python之基础一
    为善如挽逆水之舟,才放手便下流
    对自己的表现打分
    anki
    解决推送数据平台
    己所独知,尽是方便;人所不见,尽是自由
    常与权
    为什么会一直刷视频而停不下来
    准备换个房子
    UDEC 1
  • 原文地址:https://www.cnblogs.com/wyzwyz/p/10859041.html
Copyright © 2020-2023  润新知