1 条题解

  • 0
    @ 2025-8-24 21:13:53

    自动搬运

    查看原文

    来自洛谷,原作者为

    avatar 听取MLE声一片
    如果我当时做的再多一点,结局会不会不同呢?

    搬运于2025-08-24 21:13:52,当前版本为作者最后更新于2021-07-30 19:13:23,作者可能在搬运后再次修改,您可在原文处查看最新版

    自动搬运只会搬运当前题目点赞数最高的题解,您可前往洛谷题解查看更多

    以下是正文


    这道题对 EK+spfa 算法不太友好,需要卡常才能通过。

    (但是好歹卡过去了)

    学习费用流(最小费用最大流)首先要学习网络流,可以看我的题解,当然可以参考经典日报

    费用流和网络流的形态很类似,主体还是根据网络流。下面举一个例子(又是借鉴日报)。

    假设 s 城有 inf个(穷)人想去 t 城,但是从 st 要经过一些城市才能到达,每条路有最大流量和权值(流量通过 1 所花费的代价),问最终最多能有多少人能到达 t 城。(由于是穷人)他们希望能在最多人到达 t 城的同时花最少的钱,问最少的钱是多少。

    费用流就是在流量最大的情况下所花费的最小费用。

    相较于网络流,费用流只是增加了权值,我们只需要解决权值问题即可。

    这你想到了什么?代价最小?那就最短路!

    因为有负权边,所以 spfa 是最方便的!而且需要进行多次 spfa 所以基本上不会全都卡成 n2n^2

    关于 spfa 它诈尸了!(大雾)

    再详细一点,就是把 bfs 改成 spfa ,再松弛过程中记录路径即可。

    这道板子题会卡一下 EK+SPFA,所以需要进行卡常。

    下面是代码:

    #include<iostream>
    #include<cstdio>
    #include<cmath>
    #include<string>
    #include<cstring>
    #include<algorithm>
    using namespace std;
    namespace in{
        #ifdef faster
        char buf[1<<21],*p1=buf,*p2=buf;
        inline int getc(){return p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?EOF:*p1++;}
        #else
        inline int getc(){return getchar();}
        #endif
        template <typename T>inline void read(T& t){
            t=0;int f=0;char ch=getc();while (!isdigit(ch)){if(ch=='-')f = 1;ch=getc();}
            while(isdigit(ch)){t=t*10+ch-48;ch = getc();}if(f)t=-t;
        }
        template <typename T,typename... Args> inline void read(T& t, Args&... args){read(t);read(args...);}
    }
    namespace out{
        char buffer[1<<21];int p1=-1;const int p2 = (1<<21)-1;
        inline void flush(){fwrite(buffer,1,p1+1,stdout),p1=-1;}
        inline void putc(const char &x) {if(p1==p2)flush();buffer[++p1]=x;}
        template <typename T>void write(T x) {
            static char buf[15];static int len=-1;if(x>=0){do{buf[++len]=x%10+48,x/=10;}while (x);}else{putc('-');do {buf[++len]=-(x%10)+48,x/=10;}while(x);}
            while (len>=0)putc(buf[len]),--len;
        }
    }
    const int inf=2147483647;
    int maxn,cost;
    int top=1,head[5001];
    int dis[5001];
    int n,m,s,t,book[5001];
    int min(int a,int b){
    	return a>b?b:a;
    }
    struct point{
        int v,w,val,next;
    }a[100001];
    struct b{
        int fa;
        int v;
    }b[5001];
    inline void add(int u,int v,int val,int w){
        a[++top].v=v;
        a[top].val=val;
        a[top].w=w;
        a[top].next=head[u];
        head[u]=top;
    }
    queue<int> q;
    inline bool spfa(){
        for(register int i=1;i<=n;i++)
        	dis[i]=inf,b[i].fa=b[i].v=book[i]=0;
        dis[s]=0;
        q.push(s);
        book[s]=1;
        while(!q.empty()){
            int u=q.front();
            book[u]=0;
            q.pop();
            for(register int i=head[u];i;i=a[i].next){
                int v=a[i].v,w=a[i].w;
                if(a[i].val>0&&dis[v]>dis[u]+w){
                    dis[v]=dis[u]+w;
                    b[v].fa=u,b[v].v=i;
                    if(book[v]==0){
                        q.push(v);
                        book[v]=1;
                    }
                }
            }
        }
        return dis[t]!=inf;
    }
    void EK(){
        while(spfa()){
            int minn=inf;
            for(register int i=t;i!=s;i=b[i].fa)
    			minn=min(minn,a[b[i].v].val);
            for(register int i=t;i!=s;i=b[i].fa){
                a[b[i].v].val-=minn;
                a[b[i].v^1].val+=minn;
            }
            maxn+=minn;
            cost+=minn*dis[t];
        }
        return;
    }
    int main()
    {
        in::read(n,m);
        s=1,t=n;
        int u,v,val,w;
        for(register int i=1;i<=m;i++){
            in::read(u,v,val,w);
            add(u,v,val,w);
            add(v,u,0,-w);
        }
        EK();
        printf("%d %d",maxn,cost);
        return 0;
    }
    
    • 1

    [图论与代数结构 601] 最小费用最大流

    信息

    ID
    6858
    时间
    1500ms
    内存
    512MiB
    难度
    5
    标签
    (无)
    递交数
    0
    已通过
    0
    上传者