最小费用最大流

  所谓最小费用最大流,就是给边再加一个单位流量的费用,

  每流过去单位流量, 就会花费这么多的费用    

我们要求的就是在最大流下的最小费用

Dinic+SPFA

 

#include<cstdio>
#include<iostream>
#include<cstring>
#include<cctype>
#include<algorithm>
#include<queue>
using namespace std;
#define int long long
#define olinr return
#define _ 0
#define love_nmr 0
#define DB double
#define inf 0x7ff
inline int read()
{
    int x=0,f=1;
    char ch=getchar();
    while(!isdigit(ch))
    {
        if(ch=='-')
            f=-f;
        ch=getchar();
    }
    while(isdigit(ch))
    {
        x=(x<<1)+(x<<3)+(ch^48);
        ch=getchar();
    }
    return x*f;
}
inline void put(int x)
{
    if(x<0)
    {
        x=-x;
        putchar('-');
    }
    if(x>9)
        put(x/10);
    putchar(x%10+'0');
}
struct DIJ
{
    int id;
    int dis;
    friend bool operator < (const DIJ &a,const DIJ &b)
    {
        return a.dis>b.dis;
    }
};
int s;
int t;
int n;
int m;
queue<int>q;
struct node
{
    int to;
    int dis;
    int nxt;
    int flow;
    int cap;
}edge[105050];
int head[10505];
int cnt=-1;
bool vis[10505];
int change[10505];
int road[10505];
int cost[10505];
int ans;
int tot;
int minn=0x7fffffff;
inline void add(int from,int to,int dis,int cap,int flow)
{
    cnt++;
    edge[cnt].cap=cap;
    edge[cnt].to=to;
    edge[cnt].nxt=head[from];
    edge[cnt].dis=dis;
    edge[cnt].flow=flow;
    head[from]=cnt;
}
inline bool dij()
{
    memset(change,0x7f,sizeof change);
    memset(cost,0x7f,sizeof cost);
    cost[s]=0;
    q.push(s);
    vis[s]=true;
    while(!q.empty())
    {
        int tp=q.front();
        q.pop();
        vis[tp]=false;
        for(int i=head[tp];i!=-1;i=edge[i].nxt)
        {
            int go=edge[i].to;
            if(cost[go]>cost[tp]+edge[i].dis&&edge[i].cap>edge[i].flow)   //spfa
            {
                cost[go]=cost[tp]+edge[i].dis;    //更新花费
                road[go]=i;   //记录路径
                change[go]=min(change[tp],edge[i].cap-edge[i].flow);  //残量取min
                if(!vis[go])
                {
                    vis[go]=true;
                    q.push(go);
                }
            }
        }
    }
    if(change[t]>1e9) return false;
    return true;
}
inline void Dinic()
{
    while(dij())
    {
        ans+=change[t];   //
        tot+=change[t]*cost[t];   //更新花费,流量*单价
        for(int i=t;i!=s;i=edge[road[i]^1].to)
        {
            edge[road[i]].flow+=change[t];  //更新
            edge[road[i]^1].flow-=change[t];
        }
    }
}
signed main()
{
    n=read();
    m=read();
    s=read();
    t=read();
    memset(head,-1,sizeof head);
    for(int a,b,c,d,i=1;i<=m;i++)
    {
        a=read();
        b=read();
        c=read();
        d=read();
        minn=min(minn,c);
        add(a,b,d,c,0);
        add(b,a,-d,0,0);
    }
    Dinic();
    put(ans);
    putchar(' ');
    put(tot);
    olinr ~~(0^_^0)+love_nmr;
}

 

不过。。。。。众所周知,SPFA他死了。。。。。。。

那么就得用dij了

然而。。。。。TM他不能处理负权啊,那咋办?

考虑加一个大数,最后再减回来?(可能炸long long QAQ)

我们给每个点定义一个势h

将转移从$dis_u=dis_v+w$ 改成$dis_u=dis_v+w+h_v-h_u$

并保证$w+h_v-h_u ge 0$

那么假如我们有一条$p_1---p_2---p_3---......p_n$的路径

那么路径长度为$w_1+w_2+w_3+.......+w_n+(h_2-h_1)+(h_3-h_2)+......+(h_n-h_{n-1})=$

后面的h就只剩起点与终点的h了,那么问题就解决了

现在要考虑的是,h怎么定义

我们把刚刚保证的式子变一下形

$w+h_vge h_u$

额  貌似。。。$w+dis_vge dis_u$

这在最短路是对于所有边恒成立的

所以我们把上一次的dis作为$h_i$每次让$h_i+=dis[i]$

#include<cstdio>
#include<iostream>
#include<cstring>
#include<cctype>
#include<algorithm>
#include<queue>
using namespace std;
#define int long long
#define olinr return
#define _ 0
#define love_nmr 0
#define DB double
#define inf 0x7ff
inline int read()
{
    int x=0,f=1;
    char ch=getchar();
    while(!isdigit(ch))
    {
        if(ch=='-')
            f=-f;
        ch=getchar();
    }
    while(isdigit(ch))
    {
        x=(x<<1)+(x<<3)+(ch^48);
        ch=getchar();
    }
    return x*f;
}
inline void put(int x)
{
    if(x<0)
    {
        x=-x;
        putchar('-');
    }
    if(x>9)
        put(x/10);
    putchar(x%10+'0');
}
struct DIJ
{
    int id;
    int dis;
    friend bool operator < (const DIJ &a,const DIJ &b)
    {
        return a.dis>b.dis;
    }
};
int s;
int t;
int n;
int m;
priority_queue<DIJ> q;
struct node
{
    int to;
    int dis;
    int nxt;
    int flow;
    int cap;
}edge[105050];
int head[10505];
int cnt=-1;
bool vis[10505];
int change[10505];
int road[10505];
int cost[10505];
int h[10505];
int ans;
int tot;
int minn=0x7fffffff;
inline void add(int from,int to,int dis,int cap,int flow)
{
    cnt++;
    edge[cnt].cap=cap;
    edge[cnt].to=to;
    edge[cnt].nxt=head[from];
    edge[cnt].dis=dis;
    edge[cnt].flow=flow;
    head[from]=cnt;
}
inline bool dij()
{
    memset(vis,false,sizeof vis);
    memset(change,0x7f,sizeof change);
    memset(cost,0x7f,sizeof cost);
    cost[s]=0;
    q.push((DIJ){s,0});
    while(!q.empty())
    {
        DIJ tp=q.top();
        q.pop();
        if(vis[tp.id]) continue;
        vis[tp.id]=true;
        for(int i=head[tp.id];i!=-1;i=edge[i].nxt)
        {
            int go=edge[i].to;
            if(cost[go]>cost[tp.id]+edge[i].dis+h[tp.id]-h[go]&&edge[i].cap>edge[i].flow)   //判断的时候带上势
            {
                cost[go]=cost[tp.id]+edge[i].dis+h[tp.id]-h[go];   //带着势
                road[go]=i;
                change[go]=min(change[tp.id],edge[i].cap-edge[i].flow);
                q.push((DIJ){go,cost[go]});
            }
        }
    }
    if(change[t]>1e9) return false;
    return true;
}
inline void Dinic()
{
    while(dij())
    {
        ans+=change[t];
        tot+=change[t]*(cost[t]-h[s]+h[t]);   //只有起点终点影响tot
        for(int i=t;i!=s;i=edge[road[i]^1].to)
        {
            edge[road[i]].flow+=change[t];
            edge[road[i]^1].flow-=change[t];
        }
        for(int i=1;i<=n;i++)
            h[i]+=cost[i];   //别忘更新h
    }
}
signed main()
{
    n=read();
    m=read();
    s=read();
    t=read();
    memset(head,-1,sizeof head);
    for(int a,b,c,d,i=1;i<=m;i++)
    {
        a=read();
        b=read();
        c=read();
        d=read();
        minn=min(minn,c);
        add(a,b,d,c,0);
        add(b,a,-d,0,0);
    }
    Dinic();
    put(ans);
    putchar(' ');
    put(tot);
    olinr ~~(0^_^0)+love_nmr;
}
原文地址:https://www.cnblogs.com/olinr/p/9593072.html