最小费用流总结(SPFA 和dijstra两种算法实现)

本文总结了最小费用流问题,通过SPFA和Dijkstra算法寻找最短增广路径。在残余流量图中,由于负环的存在性矛盾,确保了算法的正确性。介绍了这两种算法在最小费用流问题中的应用,如二分图最小权匹配和最大权匹配。同时,文章提及在特定情况下,Dijkstra算法的性能可能不如SPFA。
摘要由CSDN通过智能技术生成

最小费用流

大致思路:

​ 在寻找增广路的前提下,只找s到t距离最短的增广路,并沿着这条路进行增广。

本代码采用SPFA进行寻找最短的增广路,如果所有 c o s t cost cost为正的,则保证残余流量图中不会出现负环。

为什么不会出现负环? 如果出现负环,代表这个环有流量,且环中的边都是反向边( c o s t cost cost为负的)。且在此之前肯定沿着环的反方向进行增广了(当时肯定是正环) ,但是如果先前在一个正环上进行了一次增广就不会是沿着最短路增广,这与先前每次增广的都是最短路矛盾!故不可能存在负环。

时间复杂度为 O ( ∣ V ∣ ∗ ∣ E ∣ 2 ∗ l o g 2 ∣ V ∣ ) ​ O(|V|*|E|^2*log_2 |V|)​ O(VE2log2V) 这是上届,一般情况都能过。

其实在增广路进行寻找时 可以用Dijkstra算法优化(引入势的概念)

最小费用流多用于指派问题,比如二分图最小权匹配(二分图的网络流图,费用为权值即可),二分图最大权匹配(把费用变为权的负值即可),还有不重叠边的多路径选取的最小权(最大权)问题。

采用SPFA的寻找最短增广路算法:

#include<bits/stdc++.h>
#define mset(a,b) memset(a,b,sizeof(a))
using namespace std;
const int maxn=220;//顶点数量
const int inf=0x3f3f3f3f;
struct edge{
   
    int to,cap,cost,rev;
    edge(){
   }
    edge(int to,int cap,int cost,int rev){
   this->to=to,this->cap=cap,this->cost=cost,this->rev=rev;}
};
class MCMF{
   
public:
    vector<edge> adja[maxn];
    int dis[maxn],prevv[maxn],preve[maxn],top;
    bool inque[maxn];
    void init(int n)
    {
   
        for(int i=0;i<n;++i)    adja[i].clear();
        top=n;
    }
    void addEdge(int u,int v,int f,int cost){
   
        adja[u].push_back(edge(v,f,cost,adja[v].size()));
        adja[v].push_back(edge(u,0,-1*cost,adja[u].size()-1));
    }
    bool spfa(int s,int t){
   
        queue<int> mp;
        mset(dis,inf);
        mset(prevv,-1);
        mset(inque,0);
        mp.push(s),prevv[s]=s,dis[s]=0,inque[s]=true;
        while(!mp.empty()){
   
            int u=mp.front();
            mp.pop();
            inque[u]=false;
            for(int i=0;i<adja[u].size();++i){
   
                edge& e=adja[u][i];
                if(e.cap>0&&dis[e.to]>dis[u]+e.cost){
   
                    dis[e.to]=dis[u]+e.cost;
                    prevv[e.to]=u;
                    preve[e.to]=i;
                    if(!inque[e.to]){
   
                        inque[e.to]=true;
                        mp.push(e.to);
                    }
                }
            
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值