网络流

网络流(EK算法)

余生长醉 提交于 2019-12-10 20:04:31
poj1273 #include <iostream> #include <cstdio> #include <cstring> #include <queue> #include <algorithm> using namespace std; #define mem(a,b) memset(a,b,sizeof(a)) #define ll long long const int maxn = 205; ll n,m; ll G[maxn][maxn]; ll pre[maxn]; //记录路径 bool flag[maxn]; bool bfs(ll be,ll en) { queue<ll> q; mem(pre,-1); mem(flag,0); q.push(be); flag[be]=1; pre[be]=be; while(!q.empty()) { ll front=q.front(); q.pop(); if(front==en) return 1; for(ll i=1;i<=n;i++) { if(!flag[i] && G[front][i]>0) //没有被标记并且可行流大于0 { flag[i]=1; pre[i]=front; q.push(i); } } } return 0; } ll EK(ll be,ll en) { ll sum=0,mi;

【网络流24题】最长k可重区间集问题

◇◆丶佛笑我妖孽 提交于 2019-12-10 02:36:43
这是一道我一开始没想出来的题。 题面 https://www.luogu.org/problemnew/show/P3358 题解 离散化。 图的基础是一条长链,流量为$k$,区间是从$l$指向$r$的边,流量为$1$,费用为长度。 #include<cstdio> #include<iostream> #include<cstring> #include<algorithm> #include<queue> #include<vector> #define ri register int #define N 5000 #define S 0 #define INF 1000000007 using namespace std; int n,k,T; int l[550],r[550],v[550],dc[1450]; int read() { int ret=0,f=0; char ch=getchar(); while (ch>'9' || ch<'0') f|=(ch=='-'),ch=getchar(); while (ch>='0' && ch<='9') ret*=10,ret+=(ch-'0'),ch=getchar(); return f?-ret:ret; } struct graph { vector<int> to,w,c; vector<int> ed[N]

网络流(1)

倾然丶 夕夏残阳落幕 提交于 2019-12-09 22:38:08
A.奇怪的游戏    处理网格图常用的黑白染色,将黑白格看成左部点和右部点,之间连边即可。   若$n*m$为偶数,那么答案具有单调性,可以直接二分答案,若当前二分出来的值最大流=应该操作的次数,那么这个值是可行的。   对于奇数的情况,黑白格权值之和的差不变,所以合法权值最多只有一个,解方程求出来,$check$一下就行了。 B.士兵占领    将"某一行至少选k个"转化为全选之后,每一行最多删掉若干个,列同理。   没有限制的格子行列之间进行连边,限制流量,之后最大流就是最多能删掉多少个,用所有格子减去最大流就是答案。 C.紧急疏散    因为答案显然具有单调性,所以直接二分答案。   因为数据范围很小,可以考虑将每个门拆成时间个,每个向汇点连流量为一的边,就可以完成对门的限制。   对于某个空地,连向所有它能走到的门,跑最大流即可。   然而这样是边数$O(n^5)$, (虽然能过)。 然后每个门向上一个时间的门连边,每个空地只向对应时间的门连边即可。 D.狼抓兔子   直接跑网络流就可以过,正解是平面图转对偶图,平面图中的一个割对应对偶图中一条路径,因此只要求出对偶图中源点到汇点的最短路即可。 E.切糕    如果没有任何限制,一个显然的建图方法是将每一列建成从源到汇的一条通路,最小割就是答案。   如果有了限制,那么只需要使得割掉两个不合法的点使得S->T仍然联通即可

网络流杂题 二

ぃ、小莉子 提交于 2019-12-09 06:49:25
A. 无限之环 正解的思路并没有局限于原图中的网络流,而是将网格图黑白染色。 将源点向黑点建边,黑点向可以连接的白点建边,之后原图无缝拼接可以简单地转化为跑最大流之后能够满流。 所以只要考虑如何加入翻转次数的限制。 因为流量必须全部流向同一个状态,简单拆分为四个方向似乎并不是可行的。 题解是将每个点拆分为四个点,分别连接对应的四个方向相邻的点,所以分类讨论: 对于四元管或无管,翻转无意义。 对于直线,题中规定不可翻转。 对于单元管,直接连上三个方向,费用分别为1 2 1就好了。 L型管和T型管比较复杂,可以直接参考代码, 思想大概是通过一些奇怪的建图,在保持原形态不变的意义下,满足翻转次数恰好与消耗费用形成匹配的关系。 因为懒得想,所以代码可以直接分类讨论 #include<bits/stdc++.h> using namespace std; const int N=2020; int n,m,s,t,tot=1,sum,f; int dis[N<<2],head[N<<2],inq[N<<2],pre[N<<2],to[N<<4],nxt[N<<4],w[N<<4],val[N<<4]; inline bool spfa(){ queue<int> q; q.push(s); memset(dis,0x3f,sizeof(dis)); dis[s]=0; while(!q

网络流总结(一)最大流

喜夏-厌秋 提交于 2019-12-08 14:39:31
网络流模型的性质 1> 容量限制 :$f(x,y)$<=$c(x,y)$ 2> 斜对称 :$f(x,y)$=-$f(y,x)$ 3> 流守恒 :除了S或者T,每个点的流出流量等于流入流量 最大流 最大流问题是指给定S和T,求出S到T的最大流量 这个图的最大流就是2,但是假如我们把这个图给skyh的话,他一定会走S->2->3->T,流量为1 之后他就写比了 我们如何该用一些反悔的操作来保证最大流呢? 用 增广路 我们把skyh的图利用斜对称的性质进行反向边加流后拿出来看一看 神奇的是,我们又发现了一条路径,所以继续流过去 最后达到了与最优解一样的效果 增广路一般会用到Ek或dinic算法 但在最大流中一般用dinic 相同的是都先用对图分层,不同的是dinic是多路增广 代码就不放啦 T1奇怪的游戏 题目描述 Blinker最近喜欢上一个奇怪的游戏。 这个游戏在一个 N*M 的棋盘上玩,每个格子有一个数。每次 Blinker 会选择两个相邻的格子,并使这两个数都加上 1。 现在 Blinker 想知道最少多少次能使棋盘上的数都变成同一个数,如果永远不能变成同一个数则输出-1。 输入格式 输入的第一行是一个整数T,表示输入数据有T轮游戏组成。 每轮游戏的第一行有两个整数N和M, 分别代表棋盘的行数和列数。 接下来有N行,每行 M个数。 输出格式 对于每个游戏输出最少能使游戏结束的次数

网络流总结

半世苍凉 提交于 2019-12-06 16:17:23
网络流不要算复杂度,远远达不到上界。但注意控制点数。 普通最大流可以处理无下界有上界的问题 最小割通常要找到性质转化为二分图。 常见转化: 要求“至少”下界但没有上界,求“最小”。反一下。先满足所有要求,再最吝啬地拿走“最大流”。 例题 《士兵占领》:行列是独立的点集,在点放兵相当于在两个集间连边。反一下走流量就成了在该行该列同时减人,跑最大流即可。 拆点:很实用的思想,也很不好想。 如果$x1$在$Y$的操作对后面有影响,或$x$的顺序影响$Y$的贡献,且影响不能通过流量和费用表示出来,那么就可把$Y$拆成多个点,表示在某尺度上的差别。 例题 《紧急疏散evacuate》:一个人通过会在同一时间同一出口后卡住后面的人,而后面的人依旧可以被鸽到下一秒,所以把门拆成k个点,t向t+1连inf边。 《修车》:最小平均即求最小总时间,倒数第i个修有贡献i*t(让自己和后边的人都等了t),这个转化很妙。对于修的顺序有不同费用,所以对人和车的关系拆点(权值乘上倒数系数),跑最小费用最大流。 最小割: 结论:最小割等于最大流 非板子,一般要找到二分图的性质。也就是说图不能太“长”。 常见模型: 多叉戟:选点有花费,点集有收益。(可以处理两种选择) $|V|$和$|E|$都是m级别 inf边表示连通必不能割。 记总收益$sum=\sum\limits_{i=1}^{m} w_i$。

网络流初步(2)

亡梦爱人 提交于 2019-12-06 10:58:44
通过颓了一个题解,终于也搞定了这个专题。 大神都颓题解。           ——By skyh 无限之环 颓题解就行了。 建图是真的恶心。不很好想。 还是自己想到了一部分,就是看到题目里说“直线形不能转”就感觉要分类讨论。 无非就那么几类:空格,单个管,L型,直线型,T型,十字形 我一直以为这道题是最小割,然后我就死掉了,思维僵化,实际上这道题是费用流。 惯性拆点,每个点拆成5个,分别是原点以及四个方向。 而且还要染色,就是那种棋盘黑白染色。 根据水管最开始的方向,将原点与剩下的4个点连边。并且根据黑白颜色讲源汇与原点连边。(我是白连源黑连汇) 然后考虑旋转,分类讨论: 单个管:这个好说,讲原有方向分别向其它方向连边,对立方向费用为2其余费用为1。 L型:它有3种旋转,改变一个支管的方向费用为1,全都改变为2,所以关键就在于改变了几个管。   以上右为例,上向下连1费用边,右向左连1费用边,这样就做到了上述要求。(注意不能是上向左,下向右,考虑实际含义) 直线型:不能旋转,不连边 T型:和单个管差不多。 十字型:不用连。 这样的话,黑白染色之后跑流,如果流量==水管接头个数/2,那么就有解,就输出最小费用,否则0。 1 #include<cstdio> 2 #include<iostream> 3 using namespace std; 4 const int xx[]={-1

P3376 模板网络流

心不动则不痛 提交于 2019-12-06 06:27:57
emmm 题目也已经很清楚了 题目链接: https://www.luogu.com.cn/problem/P3376 #include <bits/stdc++.h> using namespace std; const int maxn=200000+5; int last[maxn],nxt[maxn*2],to[maxn*2],wi[maxn*2],cnt=-1; int deep[maxn]; int s,t,n,m; void add(int u,int v,int w) { to[++cnt]=v; wi[cnt]=w; nxt[cnt]=last[u]; last[u]=cnt; return ; } bool bfs() { queue < int > Q; memset(deep,0,sizeof(deep)); while(!Q.empty()) Q.pop(); Q.push(s); deep[s]=1; do{ int u=Q.front(); Q.pop(); for(int i=last[u];i!=-1;i=nxt[i]) if(wi[i]>0 && deep[to[i]]==0) { deep[to[i]]=deep[u]+1; Q.push(to[i]); } }while(!Q.empty()); if(deep[t]==0) return 0

网络流最大流

眉间皱痕 提交于 2019-12-06 06:26:33
这应该算是网络流里面最简单的了 但我依旧是一脸懵逼(毕竟老师在讲的时候因为看不见白板就自己在自闭地看着博客) 但我还是找到了可读性极强的博客,并且懂得了皮毛 可读性极强的博客: https://www.cnblogs.com/SYCstudio/p/7260613.html#4331173 通常情况 首先对于最大流的一般例题通常都是类似于:有一座城有无限的水,另一座想通过一些管道获得尽可能多的水 概念 首先 (我发现我好喜欢首先啊) 要理解几个概念 1.源点(无限水城):只有流出去的边 2.汇点(不水城 (没有信仰,缺少划水精神的城) ):只有流进来的边 3.容量(管道允许的最大流量) 4.流量(目前管道流过的水量) 5.残量:容量 - 流量 几个基本性质 基本性质一: 对于任何一条流,总有流量<=容量 这是很显然的 基本性质二 对于任何一个不是源点或汇点的点u,总有 ∑ p ∈ E k [ p ] [ u ] == ∑ q ∈ E k [ u ] [ q ] (其中k[i][j]表示i到j的流量) ∑p∈Ek[p][u]==∑q∈Ek[u][q](其中k[i][j]表示i到j的流量) 这个也很显然,即一个点(除源点和汇点)的入流和出流相等 基本性质三 对于任何一条有向边(u,v),总有 k [ u ] [ v ] == − k [ v ] [ u ] k[u][v]==−k[v]