最小费用最大流 模版

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


 

带有费用的网络流图: 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 
posted @ 2012-05-03 21:45  Szz  阅读(1833)  评论(0编辑  收藏  举报