zoukankan      html  css  js  c++  java
  • 最小费用最大流问题及ADT

    在总流量最大的前提下,总费用最小的流为最小费用最大流。

    分别用$c$和$a$表示每条边的容量和费用。

    和最大流问题的区别要注意的是:可能存在平行边,它们的费用不同,所以无法合并这两条弧。(先假设图存在平行边和反向边),这样就可以用邻接矩阵cap和cost来保存各边的容量和费用了。

    最小费用路算法和EK算法类似,但是每次用Bellman-Ford算法来找增广路。只要初始流是该流量下的最小费用可行流,每次增广后的新流都是新流量下的最小费用流。

    cost最好用longlong保存减小溢出可能

    ADT:

     1 #include <iostream>
     2 #include <vector>
     3 #include <queue>
     4 using namespace std;
     5 
     6 const int INF = 1000000000;
     7 const int maxn = 1000;
     8 
     9 struct Edge{
    10     int from, to, cap, flow, cost;
    11     Edge(int u, int v, int c, int f, int w):from(u), to(v), cap(c), flow(f), cost(w){}
    12 };
    13 
    14 struct MCMF{
    15     int n,m;
    16     vector<Edge> edges;
    17     vector<int> G[maxn];
    18     int inq[maxn]; //是否在队列中
    19     int d[maxn]; //Bellman-Ford
    20     int p[maxn]; //上一条弧
    21     int a[maxn]; //可改进量
    22     
    23     void init(int n){
    24         this->n = n;
    25         for(int i=0;i<n;i++){
    26             G[i].clear();
    27         }
    28         edges.clear();
    29     }
    30     
    31     void AddEdge(int from, int to, int cap, int cost){
    32         edges.push_back(Edge(from,to,cap,0,cost));
    33         edges.push_back(Edge(to,from,0,0,-cost));
    34         m = edges.size();
    35         G[from].push_back(m-2);
    36         G[to].push_back(m-1);
    37     }
    38     
    39     bool BellmanFord(int s, int t, int& flow, long long& cost){
    40         for(int i=0;i<n;i++){
    41             d[i] = INF;
    42         }
    43         memset(inq, 0, sizeof(inq));
    44         d[s] = 0;
    45         inq[s] = 1;
    46         p[s] = 0;
    47         a[s] = INF;
    48         
    49         queue<int> Q;
    50         Q.push(s);
    51         while(!Q.empty()){
    52             int u = Q.front();
    53             Q.pop();
    54             inq[u] = 0;//出队
    55             for(int i =0;i<G[u].size();i++){
    56                 Edge& e=edges[G[u][i]]; //用e(带地址符)来代替后面一长串是很方便的写法,表示这条边
    57                 if(e.cap>e.flow&&d[e.to]>d[u]+e.cost){
    58                     d[e.to] = d[u]+e.cost;
    59                     p[e.to] = G[u][i];
    60                     a[e.to] = min(a[u],e.cap-e.flow);
    61                     if(!inq[e.to]){
    62                         Q.push(e.to);
    63                         inq[e.to] = 1;
    64                     }
    65                 }
    66             }
    67         }
    68         if(d[t]==INF){
    69             return false;
    70         }
    71         flow += a[t];
    72         cost += (long long)d[t]*(long long)a[t];
    73         for(int u=t;u!=s;u=edges[p[u]].from){
    74             edges[p[u]].flow += a[t];
    75             edges[p[u]^1].flow -= a[t]; //反向边(在edge中两条边相邻)
    76         }
    77         return true;
    78     }
    79     
    80     //需要保证初始网络中没有负权圈(BellmanFord不能处理)
    81     int MincostMaxflow(int s, int t, long long& cost){
    82         int flow = 0;
    83         cost = 0;
    84         while(BellmanFord(s, t, flow, cost));
    85         return flow;
    86     }
    87 };
  • 相关阅读:
    韩信的糊涂
    用友U8两个怪问题
    写给对前途迷茫的朋友:五句话定会改变你的人生
    换博客了
    各种杀毒工具的优缺点
    又是一年中秋到 别有一般更思乡
    谁说黑夜是孤单的
    李想:创业不一定是创办企业
    SQ小组KTV点歌系统简介
    注意!在subList生成子列表之后,一定不要随便更改原列表
  • 原文地址:https://www.cnblogs.com/cmbyn/p/8612926.html
Copyright © 2011-2022 走看看