最小费用流 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;

}
 

 


 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值