前置知识:最大流问题
最小费用最大流问题: 在最大流问题基础上,为每条边赋值单位流量的花费。求解保证最大流时,最小花费为多少。(因为最大流可以有多种流分配方案)

以EK算法为基础,在bfs时增加求最短路即可(单位流量花费作为最短路权值)。每次寻找增广路都要找一次最短路,找到后,该增广路的最小花费为 流量*最短路 ,然后把所有的增广路的最小花费求和即为总的最小花费。

最大费用只需建图时费用取反,跑最小费用流,结果取反即可。

存取边时有两种实现,邻接矩阵和链式前向星,链式前向星较复杂,但空间占用低。当节点数n>5000时,应考虑链式前向星做法。

后续内容是针对有向图的,无向图需要特殊处理:(参考无向图的最大流与费用流)


例题:P3381 【模板】最小费用最大流

1.邻接矩阵做法:(例题MLE3个点)

//EK,邻接矩阵
#include<bits/stdc++.h>
#define MAXN 5001
using namespace std;struct EDGE
{int v;//容量int flow;//流量int f;
};int n,m,s,t,u,v,c,f,maxn,noMore=0;
int sum;
int minflow[MAXN];
int p[MAXN],dis[MAXN],inq[MAXN];
EDGE a[MAXN][MAXN];
list<short>link[MAXN];int bfs()//找一个新的增广路
{sum=0;for(int i=1;i<=n;i++){minflow[i]=0;dis[i]=maxn;inq[i]=0;}//每次bfs要把之间存的最小剩余容量清除minflow[s]=maxn;p[s]=0;//p[]数组存这个节点的流是从哪个节点来的dis[s]=0;inq[s]=1;queue<short>q;q.push(s);while(!q.empty()){int now=q.front();q.pop();inq[now]=0;for(auto& i:link[now]){if(a[now][i].v-a[now][i].flow>0 && dis[now]+a[now][i].f<dis[i]){//如果没有访问过且有剩余容量minflow[i]=min(minflow[now],a[now][i].v-a[now][i].flow);//记录流向这个节点的最小剩余容量p[i]=now;dis[i]=dis[now]+a[now][i].f;if(!inq[i]){q.push(i);inq[i]=1;}}}//if(minflow[t]!=0){sum=minflow[t];break;}}sum=minflow[t];if(sum==0){noMore=1;return 0;}//如果t节点没有被更新,说明没有增广路了int e=t;while(p[e]!=0){a[p[e]][e].flow+=sum;//正向边加a[e][p[e]].flow-=sum;//反向边减e=p[e];}return sum;
}int main()
{std::ios::sync_with_stdio(false);maxn=pow(2,31)-1;cin>>n>>m>>s>>t;for(int i=1;i<=m;i++){cin>>u>>v>>c>>f;link[u].push_back(v);link[v].push_back(u);//反向边a[u][v].v+=c;//要用+,而不是直接覆盖赋值(考虑两节点有多条边时)a[u][v].f=f;a[v][u].f=-f;}int ans=0,temp,ans2=0;while(noMore==0){temp=bfs();ans+=temp;ans2+=temp*dis[t];}cout<<ans<<" "<<ans2;return 0;
}

2.链式前向星做法(AC)

//EK,链式前向星
#include<bits/stdc++.h>
#define MAXN 100005//至少2n大小
using namespace std;struct EDGE
{int to;int c;//容量int flow;//流量int f,next;
};int n,m,s,t,u,v,c,f,maxn,noMore=0;
int sum;
int minflow[MAXN];
int p[MAXN],dis[MAXN],inq[MAXN];
EDGE a[MAXN];
int head[MAXN],cnt_edge=-1,last[MAXN];void add_edge(int from,int to,int c,int f){a[++cnt_edge].next=head[from];a[cnt_edge].to=to;a[cnt_edge].c=c;a[cnt_edge].f=f;head[from]=cnt_edge;
}int bfs()//找一个新的增广路
{sum=0;for(int i=1;i<=n;i++){minflow[i]=0;dis[i]=maxn;inq[i]=0;}//每次bfs要把之间存的最小剩余容量清除minflow[s]=maxn;p[s]=0;//p[]数组存这个节点的流是从哪个节点来的queue<int>q;q.push(s);dis[s]=0;inq[s]=1;while(!q.empty()){int now=q.front();q.pop();inq[now]=0;for(int i=head[now];i!=-1;i=a[i].next){if(a[i].c-a[i].flow>0 && dis[now]+a[i].f<dis[a[i].to]){//如果没有访问过且有剩余容量minflow[a[i].to]=min(minflow[now],a[i].c-a[i].flow);//记录流向这个节点的最小剩余容量p[a[i].to]=now;dis[a[i].to]=dis[now]+a[i].f;last[a[i].to]=i;if(!inq[a[i].to]){q.push(a[i].to);inq[a[i].to]=1;}}}//if(minflow[t]!=0){sum=minflow[t];break;}}sum=minflow[t];if(sum==0){noMore=1;return 0;}//如果t节点没有被更新,说明没有增广路了int e=t;while(p[e]!=0){a[last[e]].flow+=sum;//正向边加a[last[e]^1].flow-=sum;//反向边减e=p[e];}return sum;
}int main()
{std::ios::sync_with_stdio(false);maxn=pow(2,31)-1;cin>>n>>m>>s>>t;for(int i=1;i<=n;i++){head[i]=-1;}for(int i=1;i<=m;i++){cin>>u>>v>>c>>f;add_edge(u,v,c,f);add_edge(v,u,0,-f);}int ans=0,temp,ans2=0;while(noMore==0){temp=bfs();ans+=temp;ans2+=temp*dis[t];}cout<<ans<<" "<<ans2;return 0;
}

记录一个无向图板子:poj 2135 Farm Tour 【无向图最小费用最大流】

//题意:给出一个无向图,问从 1 点到 n 点然后又回到一点总共的最短路。
#include <iostream>
#include <algorithm>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <vector>
#include <queue>
#include <cstring>
using namespace std;
const int N = 1050;
const int inf = 0x3f3f3f3f;
#define Del(a,b) memset(a,b,sizeof(a))
struct Node
{int from,to,cap,flow,cost;
};
vector<int> v[N];
vector<Node> e;
void add_Node(int from,int to,int cap,int cost)
{e.push_back((Node){from,to,cap,0,cost});e.push_back((Node){to,from,0,0,-cost});int len = e.size()-1;v[to].push_back(len);v[from].push_back(len-1);
}
int vis[N],dis[N];
int father[N],pos[N];
bool BellManford(int s,int t,int& flow,int& cost)
{Del(dis,inf);Del(vis,0);queue<int> q;q.push(s);vis[s]=1;father[s]=-1;dis[s] = 0;pos[s] = inf;while(!q.empty()){int f = q.front();q.pop();vis[f] = 0;for(int i=0; i<v[f].size(); i++){Node& tmp = e[v[f][i]];if(tmp.cap>tmp.flow && dis[tmp.to] > dis[f] + tmp.cost){dis[tmp.to] = dis[f] + tmp.cost;father[tmp.to] = v[f][i];pos[tmp.to] = min(pos[f],tmp.cap - tmp.flow);if(vis[tmp.to] == 0){vis[tmp.to]=1;q.push(tmp.to);}}}}if(dis[t] == inf)return false;flow += pos[t];cost += dis[t]*pos[t];for(int u = t; u!=s ; u = e[father[u]].from){e[father[u]].flow += pos[t];e[father[u]^1].flow -= pos[t];}return true;
}
int Mincost(int s,int t)
{int flow = 0, cost = 0;while(BellManford(s,t,flow,cost)){}return cost;
}
void Clear(int x)
{for(int i=0; i<=x; i++)v[i].clear();e.clear();
}int main()
{int n,m;while(~scanf("%d%d",&n,&m)){for(int i=0;i<m;i++){int x,y,z;scanf("%d%d%d",&x,&y,&z);add_Node(x,y,1,z);add_Node(y,x,1,z);}int s = 0 ,t = n+1;add_Node(s,1,2,0);add_Node(n,t,2,0);int ans = Mincost(s,t);printf("%d\n",ans);Clear(n+1);}return 0;
}

网络流:最小费用最大流问题相关推荐

  1. 最小费用最大流问题与算法实现(Bellman-Ford、SPFA、Dijkstra)

    摘要 今日,对最小费用最大流问题进行了一个简单的研究,并针对网上的一些已有算法进行了查找和研究.博客和资料很多,但是留下的算法很多运行失败.出错,或者意义不明.这里,个人对其中的Bellman-For ...

  2. 最小费用最大流问题详解

    最小费用最大流问题 一.问题描述 在网络中求一个最大流f,使流的总输送费用最小. b(f)=∑(vi,vj)bijfijb(f) = \sum\limits_{(v_i,v_j)} b_{ij} f_ ...

  3. 网络流--最小费用最大流 (理解)

    1.什么是最小费用最大流问题 上篇文章我们讲解了最大流问题,那什么是最小费用最大流呢?听名字就可以看出,我们要在满足最大流的同时找到达成最大流的最小费用. 对于一个网络流,最大流是一定的,但是组成最大 ...

  4. mysql最小费用最大流问题_最小费用最大流问题

    复杂网络中,单源单点的最小费用最大流算法(MCMF)应用广泛. 在实际网络问题中,不仅考虑从 Vs到 Vt的流量最大,还要考虑可行流在网络传送过程中的费用问题,这就是网络的最小费用最大流问题. 最小费 ...

  5. 数学建模常用Matlab/Lingo/c代码总结系列——最小费用最大流问题

    例 19(最小费用最大流问题)(续例18)由于输油管道的长短不一或地质等原因, 使每条管道上运输费用也不相同,因此,除考虑输油管道的最大流外,还需要考虑输油 管道输送最大流的最小费用.图 8 所示是带 ...

  6. 最小生成树、最大流、最小费用最大流问题精简

    最小生成树.最大流.最小费用最大流问题精简 最小生成树:   简单来说即图中一个使各点连通的N-1个边的子图,当边权和最小时为最小生成树. 经典Prim,Kruskal算法: (1)Prim:(从点出 ...

  7. mysql最小费用最大流问题_图论-网络流之最小费用最大流问题

    n=5;C=[0 15 16 0 0 0 0 0 13 14 0 11 0 17 0 0 0 0 0 8 0 0 0 0 0]; %弧容量 b=[0 4 1 0 0 0 0 0 6 1 0 2 0 3 ...

  8. poj3422 Kaka's Matrix Travels(最小费用最大流问题)

    1 /* 2 poj3422 Kaka's Matrix Travels 3 不知道 k次 dp做为什么不对??? 4 看了大牛的代码,才知道还可以这样做! 5 开始没有理解将a 和 a' 之间建立怎 ...

  9. 网络流----最小费用最大流(EK+SPFA)

    先来介绍一下什么是费用流(部分内容参考bilibili董晓算法) 给定一个网络G=(V,E),每条边有容量限制w(u,v),还有单位流量的费用c(u,v). 当(u,v)的流量为f(u,v)时,需要花 ...

最新文章

  1. 动态检测secure日志文件,iptables拒绝恶意IP
  2. 一键将Word转换为MarkDown
  3. 用C语言写的程序如何控制计算机硬件?
  4. 木马捆绑器设计思路和源码
  5. 使用ubuntu过程中遇到的问题汇总
  6. [html]html实现页面跳转都有哪些方法?
  7. 计算机网络交换机组网及虚拟局域网实验报告,计算机网络实验报告材料(虚拟局域网).doc...
  8. python读写excel模块pandas_python3 基于pandas读写Excel
  9. Angular Taskmgr 登录
  10. 审批工作流及数据库设计
  11. 从wireshark 抓包中的导出 H.264 变成可用暴风直接播放的H264 裸码流文件
  12. Boxplot(箱形图或盒图)的介绍和使用
  13. [王垠系列]TeXmacs:一个真正“所见即所得”的排版系统
  14. 基于com的delphi和matlab接口编程研究,基于COM组件的VB与MATLAB接口编程(续)
  15. 谷歌手机地图中文java_谷歌地图开发(1)使用MapView显示地图
  16. ch341a刷写华擎(ASROCK)主板BIOS教程
  17. 百格活动独家推出执行者晋升管理层的必备指南——《活动执行手册-思维篇》
  18. Java数据类型之Java数据类型的划分方式
  19. 生产制造业ERP系统模块
  20. 聊聊AIOps落地监控报警的应对之策

热门文章

  1. 【python】使用pyQT5显示网页
  2. 减肥运动心率公式小脚本
  3. java 正则 连续数字_Java - 正则表达式匹配字符串中的连续数字或字符
  4. 百度地图js中地理围栏算法bug
  5. xshell mysql中文乱码_xshell解决中文乱码
  6. 计算机考研901的学校,天津大学初试专业课科目取消902软件工程改考901
  7. 第六十三章 SQL函数 IFNULL
  8. php mysql ifnull函数_MYSQL中的IFNULL函数
  9. 杭电刘春英老师写给计算机专业学生的一些忠告
  10. 华为C8816电信版ROOT过程