网络流专题(最大流与费用流)(一)

流量网络
• 想要将一些水从S运到T,必须经过一些水站,链接水站的是管道,每条管道都有它的最大能容纳的水量,求最多S到T能流多少流量。
在这里插入图片描述
基本概念
• 这是一个典型的网络流模型。我们先了解网络流的有关定义和概念。
• 若有向图G=(V,E)满足下列条件:

  1. 有且仅有一个顶点S,它的入度为零,即d-(S) = 0,这个顶点S便称为源点,或称为发点。
  2. 有且仅有一个顶点T,它的出度为零,即d+(T) = 0,这个顶点T便称为汇点,或称为收点。
  3. 每一条弧都有非负数,叫做该边的容量。边(vi, vj)的容量用cij表示。
    • 则称之为网络流图,记为G = (V, E, C)
    在这里插入图片描述
    1 .水流不递增
    2 .不能存水
    3 流入多少水流出多少水

可改进路(增广路)

在这里插入图片描述

残留网络

在这里插入图片描述

割切

在这里插入图片描述
找一个方法,把S和T断开,所切截面为流量
所能通过的水流为截面,
所以最大流等于最小割

流量算法的基本理论

• 定理1:对于已知的网络流图,设任意一可行流为f,任意一割切为(U, W),必有:V(f) ≤ C(U, W)。
• 定理2:可行流f是最大流的充分必要条件是:f的残量网络中不存在可改进路。
• 定理3:整流定理——
如果网络中所有的弧的容量是整数,则存在整数值的最大流。
• 定理4:最大流最小割定理——
最大流等于最小割,即max V(f) = min C(U, W)。

方法:

Ford-Fulkson方法
FF方法

Edmond-Karp算法

• EK算法是FF方法中最简单的一个,当然效率也就比较低
• EK算法的流程与ff方法完全相同,只是在寻找增广路的时候使用了BFS
• 时间复杂度O(n*m^2)
• 空间复杂度O(n^2)(邻接矩阵)
• 注意要退流哦!!!!
复杂度太高基本不用
在这里插入图片描述

代码:

#include<bits/stdc++.h>
using namespace std;
const int maxn=205;
const int inf=0x7fffffff;
int r[maxn][maxn]; //残留网络,初始化为原图
bool visit[maxn];
int pre[maxn];
int m,n;
bool bfs(int s,int t)  //寻找一条从s到t的增广路,若找到返回true
{int p;queue<int > q;memset(pre,-1,sizeof(pre));memset(visit,false,sizeof(visit));pre[s]=s;visit[s]=true;q.push(s);while(!q.empty()){p=q.front();q.pop();for(int i=1;i<=n;i++){if(r[p][i]>0&&!visit[i]){pre[i]=p;visit[i]=true;if(i==t) return true;q.push(i);}}}return false;
}
int EdmondsKarp(int s,int t)
{int flow=0,d,i;while(bfs(s,t)){d=inf;for(i=t;i!=s;i=pre[i])d=d<r[pre[i]][i]? d:r[pre[i]][i];for(i=t;i!=s;i=pre[i]){r[pre[i]][i]-=d;r[i][pre[i]]+=d;}flow+=d;}return flow;
}int main()
{while(scanf("%d%d",&m,&n)!=EOF){int u,v,w;memset(r,0,sizeof(r));///for(int i=0;i<m;i++){scanf("%d%d%d",&u,&v,&w);r[u][v]+=w;}printf("%d\n",EdmondsKarp(1,n));}return 0;
}

Sap算法

• sap算法是采用了距离标号的方法求最短增广路, 而距离标号的思想来自于push__relable(压入重标记)类算法
• 有兴趣的同学可以去了解一下push__relable类算法

int dfs(int x,int flow)
{if(x==t)return flow;//如果是汇点,从x流到t的流量 int sum=0;//当前情况下x流出多少流量 for(int i=1;i<=m;i++) {if(g[x][i]&&(d[x]==d[i]+1))//g[x][i]:x可以流到i {int tmp=dfs(i,min(g[x][i],flow-sum));//受限于x到i的边和剩余流量 g[x][i]-=tmp; g[i][x]+=tmp;//反向边 sum+=tmp;//流出tmp流量 if(sum==flow)return sum;//如果所有流量用完了 //如果流量没有用完,继续循环 }}if(d[S]==-1)return sum;//出现断层,已经断开 cntd[d[x]]--;//cntd[i]第i层有多少点   d[x]层的点 if(!cntd[d[x]])//这层没点了 ,说明出现断层 d[S]=-1;    //S最多在第m-1层,当出现在第-1层说明为不合理情况,要退出 ,相当于退出标记 d[x]++;//上升一层 cntd[d[x]]++;//层数点加1 return sum;
}dfs(S,inf);

Dinic算法

• Dinic算法是一个基于“层次图”的时间效率优先的最大流算法。
• 层次图是什么东西呢?层次,其实就是从源点走到那个点的最短路径长度。
• 于是乎,我们得到一个定理:从源点开始,在层次图中沿着边不管怎么走,经过的路径一定
是终点在剩余图中的最短路。

• Dinic算法也有类似于sap的为顶点定标的过程——通常用BFS实现……
• 每次从源点开始遍历,如果一次bfs可以从源点到汇点整个网络都会变成一个层次网络
• 在一个分层网络中, 只有a[i] = = a[j] or a[i] = = a[j] -1时<i,j>才有边存在。
• 当且仅当a[i] == a[j] -1时,两点之间的边才被称为有用边,在接下来的寻找增广路的过程中只会走这样的有用边。
• 因此,dfs的时候只要遍历到汇点即可因为同一层和下一层都更新不了汇点了


bool makelevel(int s,int t)
{memset(d,0,sizeof(d));memset(q,0,sizeof(q));d[s]=1;//s的层级为1int l=0,r=0;q[r++]=s;while(l<r){int x=q[l++];if(x==t)return 1;//到汇点时退出for(int i=head[x];i;i=edge[i].next){if((d[edge[i].t]==0)&&(edge[i].w!=0))//容量为0的边不能走&&该点的层级未被标记{q[r++]=edge[i].t;d[edge[i].t]=d[x]+1;//层级加一}}}return false;
}
int dfs(int x,int flow,int t)//从s到x流了多少流量
{if(x==t)return flow;int sum=0;for(int i=head[x];i;i=edge[i].next){if((edge[i].w!=0)&&(d[edge[i].t]==d[x]+1))//满足层级要求{int tmp=dfs(edge[i].t,min(flow-sum,edge[i].w),t);edge[i].w-=tmp;edge[i^1].w+=tmp;sum+=tmp;if(sum==flow)return sum;}}return sum;
}
while(makelevel(1,m))
{ans+=dfs(1,INF,m);
}

完整代码:

#include <bits/stdc++.h>
using namespace std;
const long long inf=2005020600;
int n,m,s,t,u,v;
long long w,ans,dis[520010];
int tot=1,now[520010],head[520010]; struct node {int to,net;long long val;
} e[520010];inline void add(int u,int v,long long w) {e[++tot].to=v;e[tot].val=w;e[tot].net=head[u];head[u]=tot;e[++tot].to=u;e[tot].val=0;e[tot].net=head[v];head[v]=tot;
}inline int bfs() {  //在惨量网络中构造分层图 for(register int i=1;i<=n;i++) dis[i]=inf;queue<int> q;q.push(s);dis[s]=0;now[s]=head[s];while(!q.empty()) {int x=q.front();q.pop();for(register int i=head[x];i;i=e[i].net) {int v=e[i].to;if(e[i].val>0&&dis[v]==inf) {q.push(v);now[v]=head[v];dis[v]=dis[x]+1;if(v==t) return 1;}}}return 0;
}inline int dfs(int x,long long sum) {  //sum是整条增广路对最大流的贡献if(x==t) return sum;long long k,res=0;  //k是当前最小的剩余容量 for(register int i=now[x];i&&sum;i=e[i].net) {now[x]=i;  //当前弧优化 int v=e[i].to;if(e[i].val>0&&(dis[v]==dis[x]+1)) {k=dfs(v,min(sum,e[i].val));if(k==0) dis[v]=inf;  //剪枝,去掉增广完毕的点 e[i].val-=k;e[i^1].val+=k;res+=k;  //res表示经过该点的所有流量和(相当于流出的总量) sum-=k;  //sum表示经过该点的剩余流量 }}return res;
}int main() {scanf("%d%d%d%d",&n,&m,&s,&t);for(register int i=1;i<=m;i++) {scanf("%d%d%lld",&u,&v,&w);add(u,v,w);}while(bfs()) {ans+=dfs(s,inf);  //流量守恒(流入=流出) }printf("%lld",ans);return 0;
}
//dinic时间复杂度:O(n^2 m).

最小费用最大流

• 带有费用的网络流图: G=(V,E,C,W) V:顶点; E:弧;C:弧的容量;W:单位流量费用。
保证s到t流量最大的前提下,所需的费用最小,这就是最小费用最大流问题.

基本思路:

把弧<i,j>的单位费用w[i,j]看作弧<i,j>的路径长度,每次找从源点s到汇点t长度最短(费用最小)的可增广路径进行增广。

  1. 最小费用可增广路
  2. 路径s到t的长度即单位流量的费用。
    • 其实就是把ek算法中的广搜改成spfa……(因为存在负权边所以得用spfa)

代码:

bool spfa(int s,int t)
{queue<int>q;for(int i=0;i<N;i++){dis[i]=INF;vis[i]=0;pre[i]=-1;}dis[s]=0;vis[s]=1;q.push(s);while(!q.empty()){int u=q.front();q.pop();vis[u]=1;for(int i=head[u];i;i=edge[i].next){int v=edge[i].to;if(edge[i].cap>edge[i].flow&&dis[v]>dis[u]+edge[i].cost){dis[v]=dis[u]+edge[i].cost;pre[v]=i;if(!vis[v]){vis[v]=1;q.push(v);}}}}if(pre[t]==-1)return 0;return 1;
}
int minCostMaxflow(int s,int t,int &cost)
{int flow=0;cost=0;while(spfa(s,t)){int Min=INF;for(int i=pre[t];i;i=pre[edge[i^1].to]){if(Min>edge[i].cap-edge[i].flow)Min=edge[i].cap-edge[i].flow;}for(int i=pre[t];i;i=pre[edge[i^1].to]){edge[i].flow+=Min;edge[i^1].flow-=Min;cost+=edge[i].cost;edge[i^1].flow+=edge[i].cost;edge[i].cost-=edge[i].cost;}flow+=Min;}return flow;
}
//返回的最大流,cost存的是最小费用 

洛谷模板题

代码:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<queue>
#define ll long long
#define inf 50000000
#define re register
using namespace std;
struct po
{int from,to,dis,nxt,w;
}edge[250001];
int head[250001],cur[1000001],dep[60001],n,m,s,t,u,num=-1,x,y,l,tot,sum,k,fa[10001];
int dis[5001],vis[5001],xb[5001],flow[5001];
inline int read()
{int x=0,c=1;char ch=' ';while((ch>'9'||ch<'0')&&ch!='-')ch=getchar();while(ch=='-')c*=-1,ch=getchar();while(ch<='9'&&ch>='0')x=x*10+ch-'0',ch=getchar();return x*c;
}
inline void add_edge(int from,int to,int w,int dis)
{edge[++num].nxt=head[from];edge[num].from=from;edge[num].to=to;edge[num].w=w;edge[num].dis=dis;head[from]=num;
}
inline void add(int from,int to,int w,int dis)
{add_edge(from,to,w,dis);add_edge(to,from,0,-dis);
}
inline bool spfa()
{memset(dis,100,sizeof(dis));memset(vis,0,sizeof(vis));queue<int> q;while(!q.empty())q.pop();for(re int i=1;i<=n;i++){fa[i]=-1;}vis[s]=1;dis[s]=0;fa[s]=0;flow[s]=inf;q.push(s);while(!q.empty()){int u=q.front();q.pop();vis[u]=0;for(re int i=head[u];i!=-1;i=edge[i].nxt){int v=edge[i].to;if(edge[i].w>0&&dis[v]>dis[u]+edge[i].dis){dis[v]=dis[u]+edge[i].dis;fa[v]=u;xb[v]=i;flow[v]=min(flow[u],edge[i].w);if(!vis[v]){vis[v]=1,q.push(v);}}}}return dis[t]<inf;
}
inline void max_flow()
{while(spfa()){int k=t;while(k!=s){edge[xb[k]].w-=flow[t];edge[xb[k]^1].w+=flow[t];k=fa[k];}tot+=flow[t];sum+=flow[t]*dis[t];}
}
int main()
{memset(head,-1,sizeof(head));int d;n=read();m=read();s=read();t=read();for(re int i=1;i<=m;i++){x=read();y=read();l=read();d=read();add(x,y,l,d);}max_flow();cout<<tot<<" "<<sum;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/318496.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

eShopOnContainers 看微服务 ①:总体概览

一、简介eShopOnContainers是一个简化版的基于.NET Core和Docker等技术开发的面向微服务架构的参考应用。该参考应用是一个简化版的在线商城/电子商务微服务参考示例应用。其包含基于浏览器的Web应用、基于Xamarin的Android、IOS、Windows/UWP 移动应用&#xff0c;以及服务端应…

网络流专题(最大流与费用流)例题总结

文章目录NC 106056 poj1459 Power Network题目大意&#xff1a;题解&#xff1a;NC213817 [网络流24题]最小路径覆盖问题题目&#xff1a;题解&#xff1a;例2&#xff1a;NC213818 [网络流24题]魔术球问题题目&#xff1a;题解&#xff1a;方法2&#xff1a;NC 213820 [网络流…

周期长度和(KMP)

文章目录题目描述解析问题总结代码题目描述 解析 我们可以看到 如果A是B的周期 那么B一定可以写成&#xff1a; A1A2A1 的形式 注意到&#xff1a;A1就是KMP中的公共前后缀 要使A最大&#xff0c;要使A1最短 也就是求最短公共前后缀 这怎么求呢&#xff1f; 我们注意到&#x…

计算几何基础-1

文章目录基本概念点与向量的运算精度问题线段&#xff0c;射线和直线点积&#xff1a;夹角叉积向量的极角旋转一个向量求三角形面积直线交点点到直线距离点在直线上的投影判断两条线段是否相交点与直线的位置关系点是否在直线左侧点是否在直线上点是否在线段上点与多边形的位置…

.net core i上 K8S(四).netcore程序的pod管理,重启策略与健康检查

目录1.pod管理2.重启策略3.健康检查4.进入容器正文上一章我们已经通过yaml文件将.netcore程序跑起来了&#xff0c;但还有一下细节问题可以分享给大家。1.pod管理1.1创建podkubectl create -f netcore-pod.yaml我们创建一个netcore-pod.yaml文件&#xff0c;内容如下&#xff1…

洛谷P2680:运输计划(倍增、二分、树上差分)

传送门 文章目录题目描述解析问题代码题目描述 解析 求最大值的最小值 容易想到二分 然后。。。就没有然后了。。。 看了题解 学会了一个新技能&#xff1a;树上差分 &#xff08;其实学长之前好像讲过。。。&#xff09; 一般的&#xff0c;对于一条A到B的路径&#xff0c;如…

计算几何基础-2

文章目录直线&#xff1a;图形&#xff1a;求垂足求两圆交点直线与圆交点多边形问题判断一个点是否在任意多边形内部Pick定理凸包求点集的凸包水平法&#xff1a;增量法&#xff1a;半平面半平面交求半平面交直线&#xff1a; struct Line{point p,v;Line(){}Line(point _p.po…

eShopOnContainers 看微服务 ②:配置 启动

一、什么是dockerDocker 是一个开源项目&#xff0c;通过把应用程序打包为可移植的、自给自足的容器&#xff08;可以运行在云端或本地&#xff09;的方式&#xff0c;实现应用程序的自动化部署。使用 Docker 的时候&#xff0c;需要创建一个应用或服务&#xff0c;然后把它和它…

判断整除(opj)(动态规划)

解析 与取模结合的动归&#xff0c;正常做即可 问题 眼瞎&#xff01;&#xff01;&#xff01; 这个序列的每个数都必须用到&#xff01;&#xff01;&#xff01; if(f[i-1][j]) f[i][j]1;上面这行就是不对的&#xff01;&#xff01;&#xff01; 头疼 仔细审题 opj的题…

[USACO09FEB]Revamping Trails G

题意&#xff1a; 约翰一共有 N 个牧场.由 MM 条布满尘埃的小径连接。小径可以双向通行。每天早上约翰从牧场 1 出发到牧场 N 去给奶牛检查身体。 通过每条小径都需要消耗一定的时间。约翰打算升级其中 K 条小径&#xff0c;使之成为高速公路。在高速公路上的通行几乎是瞬间完…

NET Core微服务之路:自己动手实现Rpc服务框架,基于DotEasy.Rpc服务框架的介绍和集成...

本篇内容属于非实用性&#xff08;拿来即用&#xff09;介绍&#xff0c;如对框架设计没兴趣的朋友&#xff0c;请略过。 快一个月没有写博文了&#xff0c;最近忙着两件事;一&#xff1a;阅读刘墉先生的《说话的魅力》&#xff0c;以一种微妙的&#xff0c;你我大家都会经常遇…

花店橱窗布置(洛谷P1854)(动态规划)

传送门 文章目录解析问题代码解析 一道很正常的动态规划 dp[i][j]表示到第j个花瓶放了第j朵花的dp最优值 注意&#xff1a;是严格使第i朵放在j瓶 找到最优解递归输出即可 问题 又是初始化的问题&#xff01;&#xff01;&#xff01; 一开始把dp赋值成负无穷时落掉了j0的一行…

P4009 汽车加油行驶问题

题目描述&#xff1a; 题解&#xff1a; 看了很多题解&#xff0c;无论什么解法都绕不开分层图 在本题中加满油的车每次可以移动K步&#xff0c;那么我们就可以建立一个K1层的分层图&#xff0c;表示汽车油量k的状态&#xff08;油量0…k&#xff09;&#xff0c;然后根据题目…

.net core i上 K8S(五).netcore程序的hostip模式

正文上一章讲了pod的管理&#xff0c;今天再分享一个pod的访问方式1.Pod的HostIP模式Pod的HostIP模式&#xff0c;可以通过宿主机访问pod内的服务&#xff0c;创建yaml文件如下apiVersion: v1 kind: Pod metadata: name: netcore-podlabels:app: netcorepod spec:containers: …

状态压缩:枚举子集(最优组队)(ybtoj)(动态规划)

解析 很裸的状压dp 但是直接暴力的话状态2n,枚举2n 乘在一起会T诶 怎么办呢&#xff1f; 使用下面这个循环&#xff0c;就可以保证只会枚举当前状态s的子集 for(int i(s-1)&s;i;i(i-1)&s){........ }证明 举举例子就挺明显了 为什么不重不漏呢&#xff1f; 首先i肯…

【活动(深圳)】告别2018之12.22 大湾区.NET Meet 大会 ,同时有网络直播

今年的 Connect(); 主题更加聚焦开发者工具生产力、开源&#xff0c;以及无服务器&#xff08;Serverless&#xff09;云服务。Visual Studio 2019 AI 智能加持的 IntelliCode、实时代码协作共享 Live Share&#xff0c;.NET Core 3.0的预览版本附带了大量更新&#xff0c;旨在…

最短路径(状压dp)(ybtoj)

解析 “bug总有de完的一天” 头疼 暴力写的话本题显然复杂度是假的 有一个很好的思路优化时间复杂度 先用dp[k][i]表示**从第k个关键点到任意i点的最短路 跑k遍 SPFA或迪杰斯特拉 即可 然后转移时可以只考虑关键点 使状态转移数大大降低 细节 头真疼 边界条件&#xff1a; …

P2403 [SDOI2010]所驼门王的宝藏(强连通分量)(拓扑排序)

文章目录题目描述解析代码洛谷传送门题目描述 解析 看题目要求很容易想到强连通分量缩点加拓扑dp 但是问题在于存图 第一感就是和暴力和每个点连边 但那样无论点数和边数都很爆炸 随后我们发现这个图非常稀疏 所以我们可以只连有宝藏的点 然而这样边数会被一行横门这样的数据…

Xamarin.Forms之UserDialogs 重制版本

在 forms 里面&#xff0c;目前使用比较多的弹出组件是 Acr.UserDialogs &#xff0c;但是这个组件有些小问题&#xff0c;比如 loading .hide 会同时把 toast 给一起关掉&#xff0c;android 下的 toast 希望是 安卓原生的toast 样子&#xff0c;而不是 底部弹出一个横条&…

H.Minimum-cost Flow

H.Minimum-cost Flow 题目&#xff1a; 其实就是给出每条边的单位费用&#xff0c;q次查询&#xff0c;每次查询改变所有边的容量&#xff08;所有边容量一样&#xff09;&#xff0c;问最后流出1流量的最小花费是多少&#xff1f; 题解&#xff1a; 暴力做法肯定是每次询问…