luogu 3376 最小费用最大流 模板

类似EK算法,只是将bfs改成spfa,求最小花费。

为什么可以呢,加入1-3-7是一条路,求出一个流量为40,那么40*f[1]+40*f[2]+40*f[3],f[1]是第一条路的单位费用,f[2]是。。。

因此可以写成40*(f[1]+f[2]+f[3]),那么f[1]+f[2]+..即求最短路类似。

另外,为什么可以这样求最小费用最大流呢,因为ek告诉你一定是从源点到汇点有一条可行路,既然每次都要选一条,一定要选最小费用的才最优。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<queue>
using namespace std;
const int maxn=100010;
int n,m,s,t,cnt,hd[maxn],dis[maxn],flow[maxn],vis[maxn],pre[maxn],last[maxn]; 
queue<int> q;
struct Edge{
    int to,nxt,flow,dis;
}edge[maxn];
void add(int u,int v,int w,int dis)
{
    cnt++;
    edge[cnt].to=v;
    edge[cnt].nxt=hd[u];
    edge[cnt].flow=w;
    edge[cnt].dis=dis;
    hd[u]=cnt;
}
int spfa(int s,int t)
{
    memset(dis,0x7f,sizeof dis);
    memset(flow,0x7f,sizeof flow);
    memset(vis,0,sizeof vis);
//    while(!q.empty()) q.pop();
    q.push(s),vis[s]=1,dis[s]=0,pre[t]=-1;
    
    while(!q.empty()) 
    {
        int u=q.front();
        q.pop();
        vis[u]=0;
        for(int i=hd[u];i!=-1;i=edge[i].nxt)
        {
            int v=edge[i].to;
            if(edge[i].flow >0 && dis[v]>dis[u]+edge[i].dis)
            {
                dis[v]=dis[u]+edge[i].dis;
                pre[v]=u;
                last[v]=i;//
                flow[v]=min(flow[u],edge[i].flow);//
                if(!vis[v])
                {
                    vis[v]=1;
                    q.push(v); 
                }
//                if(v==t) return 1;//已经到达,但不一定是最短路,晕,哈哈想成之前的bfs了。。。 
            }
        }
    }
//    return 0;
    return pre[t]!=-1;
}
int mxflow=0,mincost=0;
void mcmf()
{
    while(spfa(s,t))//往下走就一定能到达 
    {
        int now=t;
        mxflow+=flow[t];
        mincost+=flow[t]*dis[t];
        while(now!=s)
        {
            edge[last[now]].flow-=flow[t];
            edge[last[now]^1].flow+=flow[t];
            now=pre[now];
        }
    }
}
int x,y,z,f;
int main()
{
    scanf("%d%d%d%d",&n,&m,&s,&t);
    memset(hd,-1,sizeof hd);cnt=-1;
    for(int i=1;i<=m;i++)
    {
        scanf("%d%d%d%d",&x,&y,&z,&f);
        add(x,y,z,f);
        add(y,x,0,-f);//顺着流一单位,逆着流一单位,相当于没流 
    }
    mcmf();
    printf("%d %d",mxflow,mincost);
}

猜你喜欢

转载自www.cnblogs.com/caterpillor/p/9254608.html