zoukankan      html  css  js  c++  java
  • 最小费用最大流 模版

    一、最小费用最大流的模型
    保证流量最大的前提下,所需的费用最小,这就是最小费用最大流问题.


     

    带有费用的网络流图: G=(V,E,C,W)
    V:顶点; E:弧;C:弧的容量;W:单位流量费用。
    任意的弧<i,j>对应非负的容量c[i,j]和单位流量费用w[i,j]。满足:
    ① 流量f是G的最大流。
    ② 在f是G的最大流的前提下,流的费用最小。

    F是G的最大流的集合(最大流不止一个):

    最小费用最大流,模板

    在最大流中寻找一个费用最小的流 f.

    二、最小费用最大流的算法
    基本思路:
        把弧<i,j>的单位费用w[i,j]看作弧<i,j>的路径长度,每次找从源点s到汇点t长度最短(费用最小)的可增广路径进行增广。
    1. 最小费用可增广路
    2. 路径s到t的长度即单位流量的费用。

    ps:是网络流EK算法的改进,在求增广路径的时候,把bfs改为带权的spfa,每次求权值最小的增广路。

    ps:要注意一点,逆边cost[i][j] = -cost[j][i],不能忘了加上去。

     1 自己的模板:邻接矩阵。
     2 
     3 #include<iostream>
     4 using namespace std;
     5 
     6  
     7 
     8 int n, ans;
     9 int cap[Max][Max], pre[Max];
    10 int cost[Max][Max], dis[Max];
    11 int que[Max];
    12 bool vis[Max];
    13 
    14  
    15 
    16 bool spfa(){                  //  源点为0,汇点为n。
    17     int i, head = 0, tail = 1;
    18     for(i = 0; i <= n; i ++){
    19         dis[i] = inf;
    20         vis[i] = false;
    21     }
    22     dis[0] = 0;// dis 表示 最小 花费
    23     que[0] = 0;
    24 
    25     vis[u] = true;
    26 
    27     while(tail != head){      //  循环队列。
    28         int u = que[head];
    29 
    30         for(i = 0; i <= n; i ++)
    31             if(cap[u][i] && dis[i] > dis[u] + cost[u][i]){    //  存在路径,且权值变小。
    32                 dis[i] = dis[u] + cost[u][i];
    33                 pre[i] = u;
    34                 if(!vis[i]){
    35                     vis[i] = true;
    36                     que[tail ++] = i;
    37                     if(tail == Max) tail = 0;
    38                 }
    39             }
    40         vis[u] = false;
    41         head ++;
    42         if(head == Max) head = 0;
    43     }
    44     if(dis[n] == inf) return false;
    45     return true;
    46 }
    47 
    48  
    49 
    50 void end(){
    51     int i, sum = inf;
    52     for(i = n; i != 0; i = pre[i])
    53         sum = min(sum, cap[pre[i]][i]);
    54     for(i = n; i != 0; i = pre[i]){
    55         cap[pre[i]][i] -= sum;
    56         cap[i][pre[i]] += sum;
    57         ans += cost[pre[i]][i] * sum;   //  cost[][]记录的为单位流量费用,必须得乘以流量。
    58     }
    59 }
    60 
    61  
    62 
    63 int main(){
    64     ....
    65     ans = 0;
    66     while(spfa()) end();
    67     ....
    68     return 0;
    69 }
     1 自己的模板:邻接表。
     2 
     3 #include<iostream>
     4 using namespace std;
     5 
     6  
     7 
     8 struct{
     9     int v, cap, cost, next, re;    //  re记录逆边的下标。
    10 }edge[eMax];
    11 int n, m, ans;
    12 int k, edgeHead[nMax];
    13 int que[nMax], pre[nMax], dis[nMax];
    14 bool vis[nMax];
    15 
    16  
    17 
    18 void addEdge(int u, int v, int ca, int co){
    19     edge[k].v = v;
    20     edge[k].cap = ca;
    21     edge[k].cost = co;
    22     edge[k].next = edgeHead[u];
    23     edge[k].re = k + 1;
    24     edgeHead[u] = k ++;
    25     edge[k].v = u;
    26     edge[k].cap = 0;
    27     edge[k].cost = -co;
    28     edge[k].next = edgeHead[v];
    29     edge[k].re = k - 1;
    30     edgeHead[v] = k ++;
    31 }
    32 
    33  
    34 
    35 bool spfa(){                  //  源点为0,汇点为n。
    36     int i, head = 0, tail = 1;
    37     for(i = 0; i <= n; i ++){
    38         dis[i] = inf;
    39         vis[i] = false;
    40     }
    41     dis[0] = 0;
    42     que[0] = 0;
    43 
    44     vis[u] = true;
    45     while(tail > head){       //  这里最好用队列,有广搜的意思,堆栈像深搜。
    46         int u = que[head ++];
    47 
    48         for(i = edgeHead[u]; i != 0; i = edge[i].next){
    49             int v = edge[i].v;
    50             if(edge[i].cap && dis[v] > dis[u] + edge[i].cost){
    51                 dis[v] = dis[u] + edge[i].cost;
    52                 pre[v] = i;
    53                 if(!vis[v]){
    54                     vis[v] = true;
    55                     que[tail ++] = v;
    56                 }
    57             }
    58         }
    59         vis[u] = false;
    60     }
    61     if(dis[n] == inf) return false;
    62     return true;
    63 }
    64 
    65  
    66 
    67 void end(){
    68     int u, p, sum = inf;
    69     for(u = n; u != 0; u = edge[edge[p].re].v){
    70         p = pre[u];
    71         sum = min(sum, edge[p].cap);
    72     }
    73     for(u = n; u != 0; u = edge[edge[p].re].v){
    74         p = pre[u];
    75         edge[p].cap -= sum;
    76         edge[edge[p].re].cap += sum;
    77         ans += sum * edge[p].cost;     //  cost记录的为单位流量费用,必须得乘以流量。
    78     }
    79 }
    80 
    81  
    82 
    83 int main(){
    84 
    85     ...
    86 
    87     ans = 0;
    88     while(spfa()) end();
    89     ...
    90 
    91     return 0;
    92 }
    93 
    94 
  • 相关阅读:
    HDU6655 Just Repeat(2019杭电多校J题)
    贪吃蛇-
    2D命令行小游戏Beta1.0
    寒假作业三
    星 辰 &#183; 第 一 条 约 定
    塔 &#183; 第 三 条 约 定
    class中的东西和继承、多态的概念
    塔 &#183; 第 一 条 约 定
    部门学习总结之类的
    作业二
  • 原文地址:https://www.cnblogs.com/acSzz/p/2481400.html
Copyright © 2011-2022 走看看