刷了23道网络题后,想写一个博客记录
概述:
网络是一个特殊的有向图(V,E),与一般的有向图特殊在于 边有容量,以及有源汇点的设计
E中每条边(u,v)有一个称为容量的权值,称为c(u,v)
V中有两个特殊点 :源点和汇点
网络中还有个概念叫流,存在于边集之中,满足以下性质
源点可以流出的流量无限大,汇点可以流入的流量无限大
容量限制: 边的流不能超过边的容量
流量守恒:对于非源点和汇点的每个顶点,流入的流量和流出的流量相同
更形式化的表示是:
网络流的建模:
和DAG(有向无环图)类似但是在建图时要连一条反向边(容量为0)用于构建残余网络
且这并不是环,是解题的一部分
关于网络流有三个经典问题
最大流问题
最小割问题
最小费用最大流问题(费用流)
最大流问题:
从模型上来说就是找到流入汇点最多的流量为多少

ps:这里1号节点流入的流量实际为2,写成5是为了更好感受这种流的概念

解决此类问题有两种算法:EK算法和Dinic算法,这里笔者认为Dinic效率更高,仅展示Dinic算法
.因为讲解Dinic的视频和文章很多,故不进行讲解
bool bfs() {
memset(d,0,sizeof(d));
queue<int> q;
q.push(s);
d[s]=1;
while(!q.empty()) {
int u=q.front();
q.pop();
for (int i=head[u];i;i=e[i].ne) {
int v=e[i].v;
if (e[i].c &&!d[v]) {
d[v]=d[u]+1;
q.push(v);
if (v==t)return true;
}
}
}
return false;
}
int cur[N];
int dfs(int u,int mf) {
if (u==t)return mf;
int sum=0;
for (int i=cur[u];i;i=e[i].ne) {
int v=e[i].v;
cur[u]=i;
if (e[i].c && d[v]==d[u]+1) {
int f= dfs(v,min(mf,e[i].c));
sum+=f;
mf-=f;
e[i].c-=f;
e[i^1].c+=f;
}
if (mf==0)break;
}
if (sum==0)d[u]=0;
return sum;
}
int Dinic() {
int flow=0;
while (bfs()) {
memcpy(cur,head,sizeof(cur));
flow+=dfs(s,INF);
}
return flow;
}
最大应用和建模


公司连向餐桌容量为1,是因为一个公司的代表不能同时去一个餐桌
最小割问题:
概述:
将V分为两个集合S,T 其中s∈S,t∈T。S∩T=空,S∪T=V
S流向T的容量之和为割
最小割就是所有划分中割最小的
最小割的性质
最小割等于最大流
最小割等于s到t不相交的路径数
求最小割等于求最大流,也是利用Dinic算法(上面已展示)
最小割应用及建模


因为实验和仪器之间的容量为INF,所以INF必然不能成为最小割,即不存在选了实验却没选对应的仪器(这样会使割无限大)
首先将我们选择的实验和选择的仪器划分进集合S,未被选入的划分进T,那么我们的割就是未被选入S的实验的奖金之和 加上选入S的仪器成本之和
而收益等于 奖金-成本 = 所有的奖金 - 未被选入的实验奖金 - 选入仪器的成本 = 所有奖金-最小割
费用流问题:
在网络的基础上,给边集的每条边加上权值,若存在多种实现最大流的方案,求出权值之和最小的方案
这里使用EK算法
bool bfs() {//SPFA
memset(mf,0,sizeof(mf));
memset(dis,0x3f,sizeof(dis));
memset(vis,0,sizeof(vis));
queue<int> q;
q.push(s);
dis[s]=0;
mf[s]=INF;
while(!q.empty()) {
int u=q.front();
q.pop();
vis[u]=false;
for (int i=head[u];i;i=e[i].ne) {
if (e[i].c && dis[e[i].v]>dis[u]+e[i].w) {
int v=e[i].v,w=e[i].w;
dis[v]=dis[u]+w;
pre[v]=i;
mf[v]=min(mf[u],e[i].c);
if (!vis[v])vis[v]=true,q.push(v);
}
}
}
return mf[t]!=0;
}
int cost,flow;
void EK() {
while (bfs()) {
for(int v=t;v!=s;) {
int i = pre[v];
e[i].c-=mf[t];
e[i^1].c+=mf[t];
v = e[i^1].v;
}
flow+=mf[t];
cost+=dis[t]*mf[t];
}
}
其他有趣的网络流:
864



被折叠的 条评论
为什么被折叠?



