北京培训记day3
网络流
一、基础知识点:
【容量网络】
图G(V,E)为有向网络,在V中指定一个源点和一个汇点,流量从源点出发经过有向网络流向汇点。对于每一条有向边有权值C,称作弧的容量。有向边称为弧。这样的有向网络称为容量网络。
【弧的流量】
容量网络G中的每条弧上的实际流量称作弧的流量。
【网络流】
有向图G中弧上流量的集合,称为网络流。
【可行流】
在容量网络中满足下列条件的网络流称为可行流。
1、弧流量限制:流量要大于等于0且小于等于弧的容量。
2、平衡条件:流量只能从源点流出经过容量网络在汇点会聚。在网络中不会凭空出现和消失。
【可行流流量】
源点的净流出流量或汇点的净流入流量。
【零流】
流量为零。
【伪流】
满足限制条件但不满足平衡条件的网络流。也称为容量可行流。
【最大流】
在容量网络中,满足弧流量限制条件和平衡条件的最大可行流,称为网络最大流,简称最大流。
【饱和弧与非饱和弧】
在容量网络中的某一条弧当流量等于容量时,此弧为饱和弧,否则为非饱和弧。
【零流弧和非零流弧】
在容量网络中的某一条弧当流量等于零时,此弧为零流弧,否则为非零流弧。
【链】
在容量网络中,顶点序列(U1,U2……Un,V)为一条链,要求两个相连的点之间有一条弧。
注意:链和有向图中有向路径不是相同概念,有向路径中有向边的方向是相同的,但链这里不要求这样。
【正方向】
设P为容量网络中源点到汇点的一条链,由源点到汇点的方向就为正方向。
【前向弧与后向弧】
方向与链的正方向相同的弧称为正向弧。反之称为后向弧。
建法:建一条容量为f的正向弧,以及一条容量为0的后向弧,运行时上减下加。
P.S.若为双向边,则建一条容量为f的正向弧和一条容量为f的反向弧。
【增广路】
在容量网络中P是从源点到汇点的一条链,如果:
1、P的所有前向弧都为非饱和弧。
2、P的所有后向弧都为非零流弧。
则称P是一条增广路(增广链或可改进路)。
沿着增广路改进可行流的操作称为增广。
【残留容量】
对于给定的容量网络中某条弧的容量为F,流量为C,残留容量就位F-C。
【残留网络】
以残留容量建成的容量网络。也称为剩余网络。
【割】
在容量网络G(V,E)中存在E'为E的子集。若G在删掉E'的所有边后不连通,E'就为G的割。因为割将G的顶点集划分为S,T两个集合。所以记割为(S,T)。若源点s在点集S中,汇点t在点集T中,则称该割为S-t割。
【割的容量】
割的所有前向弧(定义源点到汇点为正方向)的容量只和。
【最小割】
割的容量最小的割称为最小割。
【割的净流量】
割中所有弧的流量之和,前向弧流量为正值,后向弧的流量为负值。
【增广路定理】
若容量网络中可行流f已经为最大流的充要条件是在容量网络中不存在增广路。
【最大流最小割定理】
对于容量网络G,其最大流量等于最小割流量。
二、dinic
计算残余网络的层次图,定义h[i]表示点i到S的最少边数,按h[i]分层,只保留不同层之间的边
在层次图中利用dfs增广直到不存在增广路
重复以上步骤,复杂度:O(m*n*n)
#include<cstdio>
#include<cstring>
#include<iostream>
#include<string>
#include<algorithm>
#include<map>
#include<vector>
using namespace std;
const int N=;
const int INF=0x3f3f3f3f;
struct Node { int to,cap,rev; };
vector<Node> v[N];
bool used[N];
void add(int from,int to,int cap)
{
Node k1,k2;
k1.to=to;k1.cap=cap;k1.rev=v[to].size();
k2.to=from;k2.cap=;k2.rev=v[from].size()-;
v[from].push_back(k1);
v[to].push_back(k2);
}
int dfs(int s,int t,int f)
{
if(s==t) return f;
used[s]=true;
for(int i=,siz=v[s].size();i<siz;i++)
{
Node &tmp = v[s][i];
if(used[tmp.to]==false && tmp.cap>)
{
int d=dfs(tmp.to,t,min(f,tmp.cap));
if(d>)
{
tmp.cap-=d;
v[tmp.to][tmp.rev].cap+=d;
return d;
}
}
}
return ;
}
int max_flow(int s,int t)
{
int flow=;
while()
{
memset(used,false,sizeof(used));
int f=dfs(s,t,INF);
if(f==)
return flow;
flow+=f;
}
}
int main()
{
int n,m;
cin>>n>>m;
for(int i=;i<n;i++)
{
int x,y,z;
cin>>x>>y>>z;
add(x,y,z);
}
cout<<max_flow(,m)<<endl;
}
三、EK(比较慢)
最小费用最大流
把dinic中的dfs换成spfa,图不分层即可
每次找最短的增广路,最终答案即为最小费用最大流
//代码未测试,可能是错的QAQ
#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
#include<queue>
#define inf 1073741823
using namespace std;
const int Mx1=;
const int Mx2=;
struct Node { int to,val,cst,nxt; } str[Mx2];
int n,m,fr,to,cost,flow,cnt,head[Mx1],pre[Mx1],edge[Mx1],dis[Mx1];
void insert(int u,int v,int val,int cst)
{
str[cnt].to=v; str[cnt].val=val;
str[cnt].cst=cst; str[cnt].nxt=head[u];
head[u]=cnt++; str[cnt].to=u; str[cnt].val=;
str[cnt].cst=-cst; str[cnt].nxt=head[v];
head[v]=cnt++;
}
bool Spfa(int s,int t)
{
queue <int> q;
memset(pre,-,sizeof(pre));
memset(dis,0x3F,sizeof(dis));
dis[s]=; pre[s]=; q.push(s);
while (!q.empty())
{
int u=q.front();q.pop();
for(int e=head[u];e!=-;e=-str[e].nxt)
{
int v=str[e].to;
if(str[e].val>&&dis[u]+str[e].cst<dis[v])
{
dis[v]=dis[u]+str[e].cst; pre[v]=u;
edge[v]=e; q.push(v);
}
}
}
if(pre[t]==-1) return false;
return true;
}
void solve(int s,int t)
{
while(Spfa(s,t))
{
int f=inf;
for(int u=t;u!=s;u=pre[u])
if(str[edge[u]].val<f)
f=str[edge[u]].val;
flow+=f; cost+=dis[t]*f;
for(int u=t;u!=s;u=pre[u])//调整容量
str[edge[u]].val-=f,str[edge[u]^].val+=f;
}
printf("%d\n",cost);
}
void build()
{
memset(head,-,sizeof(head));
//balabala.....
}
int main()
{
scanf("%d%d%d%d",&n,&m,&fr,&to);
build();
solve(fr,to);
return ;
}
三、有上下界的网络流
要消除下界,也就是把下界化为0,则要先将下界的流量统计上

若无源汇则不用加S-T的边,有源汇只能在DAG上跑
上图直接从超级源点向超级汇点跑最大流(最小费用最大流)即可得到一组可行流
删掉原来汇点到源点之间的边
在残余网络上从原来的源点向汇点跑一遍最大流,与可行流相加即为最大流
在残余网络上从原来的汇点向源点跑一边最大流,用可行流减去即为最小流
北京培训记day3的更多相关文章
- 北京培训记day5
高级数据结构 一.左偏树&斜堆 orz黄源河论文 合并,插入,删除根节点 打标记 struct Node { int fa,l,r,w,dep } tree[Mx]; int Merge(in ...
- 北京培训记day2
后缀三姐妹 P.S.后缀大家族关系:后缀自动机fail指针=后缀树,后缀树前序遍历=后缀数组 一.后缀数组:orz罗穗骞集训队论文 给每个后缀按字典序排序 rank[]表示从i开始的后缀排名多少 sa ...
- 北京培训记day1
数学什么的....简直是丧心病狂啊好不好 引入:Q1:前n个数中最多能取几个,使得没有一个数是另一个的倍数 答案:(n/2)上取整 p.s.取后n/2个就好了 Q2:在Q1条件下,和最小为多少 答 ...
- 北京培训记day4
智商题QAQ-- T1:求>=n的最小素数,n<=10^18 暴力枚举n-n+100,miller-rabin筛法 T2:给定一个01矩阵,每次选择一个1并将(x,y)到(1,1)颜色反转 ...
- 福建省队集训被虐记——DAY3
昨天没写--今天补上吧 一如既往的跪了 棋盘 [问题描述] 给出一个N*M的方格棋盘,每个格子里有一盏灯和一个开关,开始的时候,所有的灯都是关着的.用(x, y)表示第x行,y列的格子.(x, y)的 ...
- 我的屌丝giser成长记-研二篇
之前有提到过的,本来按照计划中,研一结束就该去深圳中科院研究所实习的,之前跟里面师兄说好了的,奈何导师又接到一个新的科研研究项目,跟学院的几个其他老师一起合作的,主要是关于土地流转系统,而且是一个挺大 ...
- Python基础篇-day3
主要内容:字典 集合 文件处理 字符编码 1.字典dict简介dict就是key value值,索引有意义,数据无序 key定义规则:a:不可变--数字.字符串.元组(可变--列表.字典)b:不能重复 ...
- .Net面试经验,从北京到杭州
首先简单说下,本人小本,目前大四软件工程专业,大三阴差阳错地选了.Net方向,也是从大三开始接触.Net.自认为在学生中.net基础还可以,嘿嘿,吹一下. 大四第一学期学校安排去北京培训,培训了两个月 ...
- Java游戏服务器成长之路——感悟篇
又是一个美好的周末啊,现在一到周末,早上就起得晚,下午困了又会睡一两个小时,上班的时候,早上起来喝一杯咖啡,然后就能高效的工作一整天,然而到了周末人就懒散了,哈哈. 最近刚跳槽,到新公司已经干了有两周 ...
随机推荐
- 如何利用FineReport制作动态树报表
在对数据字段进行分类管理时,利用动态树折叠数据是一个很好的方法,也就是点击数据前面的加号才展开对应下面的数据,如下图.那这样的效果在制作报表时该如何实现呢? 下面以报表工具FineReport为例介绍 ...
- 利用BI搭建零售业数据信息平台
某百货公司是全市规模最大的以零售为主.多元化经营的股份制商业企业.拥有员工数千人,经营国内外品牌2300余种,年商品销售额逾10亿人元. 销售体量如此庞大的企业近几年在IT建设上出现了问题,集团内部的 ...
- iOS 应用程序生命周期
开发应用程序都要了解其生命周期. 今天我们接触一下iOS应用程序的生命周期, iOS的入口在main.m文件: int main(int argc, char * argv[]) { @autorel ...
- mybatis-generator-gui--一个mybatis代码自动生成界面工具
mybatis-generator-gui是什么 介绍mybatis-generator-gui之前,有必要介绍一下什么是mybatis generator(熟悉的同学可以跳过这一节).我们都知道,通 ...
- 实现CheckBox的三种选中状态(全选、半选、不选)在GridView中模拟树形的功能
度娘了很多帖子,只说三种状态要用图片替换来做,但没找到有用的例子,被逼自己写了一个 三方控件肯定是很多的,如jstree,可以直接用 由于公司的UDS限制,不能上传图片,只能文字说明了. 就是要在gr ...
- Oracle常用函数汇总
在Oracle OCP考试中,相当一部分知识点涉及到对于Oracle常见函数的考查.尽管Oracle官方文档SQL Language Reference中Functions一章内列举了所有Oracle ...
- Ubuntu16.04 LTS下apt安装WireShark
Ubuntu16.04 LTS下apt安装WireShark 安装与配置 首先通过apt安装WireShark: $ sudo apt install wireshark 会同时安装许多的依赖包,其中 ...
- Intellij IDEA 一些不为人知的技巧
Intellij IDEA 一些不为人知的技巧 2016/12/06 | 分类: 基础技术 | 0 条评论 | 标签: IntelliJ 分享到:38 原文出处: khotyn 今天又听了 Jetbr ...
- [No000098]SVN学习笔记5-分支,合并,属性,补丁,锁,分支图
行结束符和空白选项 在项目的生命周期中,有时可能会将行结束符由 CRLF 改为 LF,或者修改一段代码的缩进.不幸的是这样将会使大量的代码行被标记为已修改,尽管代码本身并没有被修改.这里列出的选项将会 ...
- HackerRank Week of Code 26
好像这次week of code不是很难= = A int main(){ int n; int m; cin >> n >> m; cout<<(n+)/*)/) ...