最小费用流 Bellman-Ford与Dijkstra 模板

今天刚接触最小费用流 码下两个版本当作模板用吧 spfa的做法明天再整理

有负权边的情况只能用Bellman-Ford 没有的话就用Dijkstra 毕竟Dijkstra效率更高

首先贴下Bellman-Ford 实现最小费用流的算法 时间复杂度为 O(FEV)   F E V 分别代表需要传输的流量 边的条数 节点的个数

// Bellman_Ford
//Bellman—Ford算法

//Bellman算法求最短增广路&最小费用流 O(FEV)
#include<algorithm>
#include<iostream>
#include<cstdlib>
#include<cstring>
#include<cstdio>
#include<string>
#include<stack>
#include<queue>
#include<cmath>
#include<stack>
#include<list>
#include<map>
#include<set>
typedef long long ll;
using namespace std;
#define MV 11000 //顶点的最大个数
#define INF 0x3f3f3f3f

struct edge
{
    int t, cap, cost, rev;
    edge(int to = 0, int c = 0, int ct = 0, int r = 0): t(to), cap(c), cost(ct), rev(r) {};
};
vector <edge> G[MV];
int dis[MV];//the distance from source
int prevv[MV], preve[MV];//the previous node and the previous edge

int min_cost_flow(int n,int v,int s, int t, int f)//与main函数中的变量意义相同
{
    
    int ans = 0, i, j;
    while(f > 0)
    {
        fill(dis, dis + v, INF);
        dis[s] = 0;
        bool update = true;
        while(update)
        {//bellman
            update = false;
            for(i = 0; i < v; ++i)
            {
                int size1 = G[i].size();
                if(dis[i] == INF)
                    continue;
                for(j = 0; j < size1; ++j)
                {
                    edge &es = G[i][j];
                    if(es.cap > 0 && dis[es.t] > dis[i] + es.cost)
                    {
                        dis[es.t] = dis[i] + es.cost;
                        prevv[es.t] = i;
                        preve[es.t] = j;
                        update = true;
                    }
                }
            }
        }
        
        if(dis[t] == INF)
            return -1;
        int d = f;
        for(i = t; i != s; i = prevv[i])
            d = min(d, G[prevv[i]][preve[i]].cap);
        
        ans += d * dis[t];
        f -= d;
        for(i = t; i != s; i = prevv[i])
        {
            edge &es = G[prevv[i]][preve[i]];
            es.cap -= d;
            G[es.t][es.rev].cap += d;
        }
    }
    return ans;
}


void addedge(int s1,int t1,int cap,int cost)//依次为边的起点 终点 容量 花费
{
    G[s1].push_back(edge(t1, cap, cost, G[t1].size()));
    G[t1].push_back(edge(s1, 0, -cost, G[s1].size() - 1));
}
int main()
{
    int n, v, s, t, f;//n 是边的条数
                      // v 节点的个数(包括源点和汇点)
                      // s source   t sink
                     // f为需要传送的流量
    return 0;
}

———————————————————————————

Dijkstra算法  复杂度为O(FElogV)     F E V 分别代表需要传输的流量 边的条数 节点的个数

#include<algorithm>
#include<iostream>
#include<cstdlib>
#include<cstring>
#include<cstdio>
#include<string>
#include<stack>
#include<queue>
#include<cmath>
#include<stack>
#include<list>
#include<map>
#include<set>
typedef long long ll;
using namespace std;


#define MV 11000 //节点最大值
#define INF 0x3f3f3f3f


struct edge
{
    int t, cap, cost, rev;
    edge(int to = 0, int c = 0, int ct = 0, int r = 0): t(to), cap(c), cost(ct), rev(r) {};
};
vector <edge> G[MV];//图的邻接表表示   注意!如果有多个样例输入 每个样例不要忘记G[i].clear();
int dis[MV];//单源点s到其它顶点的最短距离(本次搜索的最小费用)
int prevv[MV], preve[MV];//最短路中的前驱结点 对应边
int h[MV];

//最小费用流Dijkstra算法

//Dijkstra算法求最小费用流核心代码:

//h[MAX_V]:导入势保证所有边均为非负边 O(FElogV)
typedef pair<int ,int >P;
int min_cost_flow(int n, int v, int s, int t, int f) //与main函数中的变量对应一致
{
    
    int i, ans = 0;
    
    memset(h,0,sizeof h);
    
    while(f > 0)
    {
        //Dijkstra算法:寻找最短路 O(ElogV)
        priority_queue<P, vector<P>, greater<P> > que;
        fill(dis, dis + v, INF);
        dis[s] = 0;
        que.push(P(0, s));
        while(!que.empty())
        {
            P p = que.top();
            que.pop();
            
            int v = p.second;
            if(dis[v] < p.first)
                continue;
            int size = G[v].size();
            
            for(i = 0; i < size; ++i)
            {
                edge es = G[v][i];//****
                if(es.cap > 0 && dis[es.t] > dis[v] + es.cost + h[v] - h[es.t])
                {
                    
                    dis[es.t] = dis[v] + es.cost + h[v] - h[es.t];
                    prevv[es.t] = v;
                    preve[es.t] = i;
                    que.push(P(dis[es.t], es.t));
                }
            }
        }
        
        if(dis[t] == INF)
            return -1;
        //更新势
        for(i = 0; i < v; ++i)
            h[i] += dis[i];
        int d = f;
        for(i = t; i != s; i = prevv[i])
            d = min(d, G[prevv[i]][preve[i]].cap);
        ans += d * h[t];
        
        f -= d;
        
        for(i = t; i != s; i = prevv[i])
        {
            edge &es =  G[prevv[i]][preve[i]];
            es.cap -= d;
            G[i][es.rev].cap += d;
        }
    }
    
    return ans;
}


void addedge(int s1,int t1,int cap,int cost)
{
    G[s1].push_back(edge(t1, cap, cost, G[t1].size()));
    G[t1].push_back(edge(s1, 0, -cost, G[s1].size() - 1));
}

int main()
{
    int n, v, s, t, f;//n 边的条数
                      // v 节点的数量(包括源点和汇点)
                      // s source  t sink
                     // f 需要传送的流量 
    return 0;
}

这两个模板与白书上的类似 可以直接拿去用 明天更新spfa();

(只能说明我现在还没有很好的理解掌握spfa算法)

    原文作者:Dijkstra算法
    原文地址: https://blog.csdn.net/Frozensmile/article/details/76563154
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞