图论网络流总结
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了图论网络流总结相关的知识,希望对你有一定的参考价值。
【图论】网络流总结
最大流部分
网络流题目的关键:看出是网络流而且确定正确的模型
最大流算法:用来解决从源点s到汇点t,整个网络最多能输送多少流量的题目
模板:
#include <cstdio> #include <cstring> #include <queue> #include <algorithm> using namespace std; const int MAXNODE = 105 * 2; const int MAXEDGE = 100005; typedef int Type; const Type INF = 0x3f3f3f3f; struct Edge { int u, v; Type cap, flow; Edge() {} Edge(int u, int v, Type cap, Type flow) { this->u = u; this->v = v; this->cap = cap; this->flow = flow; } }; struct Dinic { int n, m, s, t; Edge edges[MAXEDGE]; int first[MAXNODE]; int next[MAXEDGE]; bool vis[MAXNODE]; Type d[MAXNODE]; int cur[MAXNODE]; vector<int> cut; void init(int n) { this->n = n; memset(first, -1, sizeof(first)); m = 0; } void add_Edge(int u, int v, Type cap) { edges[m] = Edge(u, v, cap, 0); next[m] = first[u]; first[u] = m++; edges[m] = Edge(v, u, 0, 0); next[m] = first[v]; first[v] = m++; } bool bfs() { memset(vis, false, sizeof(vis)); queue<int> Q; Q.push(s); d[s] = 0; vis[s] = true; while (!Q.empty()) { int u = Q.front(); Q.pop(); for (int i = first[u]; i != -1; i = next[i]) { Edge& e = edges[i]; if (!vis[e.v] && e.cap > e.flow) { vis[e.v] = true; d[e.v] = d[u] + 1; Q.push(e.v); } } } return vis[t]; } Type dfs(int u, Type a) { if (u == t || a == 0) return a; Type flow = 0, f; for (int &i = cur[u]; i != -1; i = next[i]) { Edge& e = edges[i]; if (d[u] + 1 == d[e.v] && (f = dfs(e.v, min(a, e.cap - e.flow))) > 0) { e.flow += f; edges[i^1].flow -= f; flow += f; a -= f; if (a == 0) break; } } return flow; } Type Maxflow(int s, int t) { this->s = s; this->t = t; Type flow = 0; while (bfs()) { for (int i = 0; i < n; i++) cur[i] = first[i]; flow += dfs(s, INF); } return flow; } void MinCut() { cut.clear(); for (int i = 0; i < m; i += 2) { if (vis[edges[i].u] && !vis[edges[i].v]) cut.push_back(i); } } } gao;
边有容量:有向边的话直接加入就能够了。假设是无向边。能够把反向边的容量定成和正向边容量一样就可以
点有容量:能够进行拆点。一个点拆成i和i‘。i作为入点,i‘作为出点,然后i和i‘之间连一条边,容量就是点的容量,然后流入i点的连向入点,流出的,从出点连出去
有一类题目是这样:先二分,然后依据二分值建图。利用最大流算法去推断,这和之前非常多图论的题目都非常类似,利用二分出来的值筛去一些边。然后推断就能够找出最大最小化的答案
有一类题目要进行模型的转化,这类题目就比較看智商了,还有经验
最小割
最大流另一个非常重要的应用,就是求最小割
下面是一些定理,事实上这些和二分图匹配里面的有点相似:
最小割 = 最大流
最大点权覆盖集 = 最小割
最小点权独立集 = 总权值 - 最大点权覆盖集
最小割的定义:把网络划分成两个集合,s,t使得在s集合和在t集合中的随意两点互相不相连,去掉的边就是割边,而这些割边代价总和就是割,最小割就是代价最小的划分方法
一类最小割的题目还是挺明显,假设是要把存在点划分两个集合。求最小代价之类的。就非常明显是最小割了
然后最小割有一些挺经典的模型:
1、平面图求最小割:
这个做法就是。把平面每一部分面积当成点,然后相邻块连边,然后增设源点s和汇点t。分别在原来的入口出口的还有一对角线上,和对应两部分边连边,这时候,每个最小割,事实上就是一个s到t的路径。那么求最短路就是最小割了
2、最小权闭合
这个做法是源点s连向正权值,负权值连向汇点t。之间关系连边容量INF,求出最小割之后,这个最小割就是最少损失。然后总权值 - 最小割得到的就是最大权闭合图的权值
关于最小割输出路径
依据题意,假设要s集合尽量多,就从t集合dfs。反之则从s集合dfs。不经过没有容量的边就可以
费用流部分:
这个就是网络有边权。代表每一份流量的代价,在求最大流的基础上,求出输送这些流量的最小代价
费用流的建模和最大流基本几乎相同,就多一个边权
费用流模板:
#include <cstdio> #include <cstring> #include <vector> #include <queue> #include <algorithm> using namespace std; const int MAXNODE = 105; const int MAXEDGE = 5005 * 4; typedef int Type; const Type INF = 0x3f3f3f3f; struct Edge { int u, v; Type cap, flow, cost; Edge() {} Edge(int u, int v, Type cap, Type flow, Type cost) { this->u = u; this->v = v; this->cap = cap; this->flow = flow; this->cost = cost; } }; struct MCFC { int n, m, s, t; Edge edges[MAXEDGE]; int first[MAXNODE]; int next[MAXEDGE]; int inq[MAXNODE]; Type d[MAXNODE]; int p[MAXNODE]; Type a[MAXNODE]; void init(int n) { this->n = n; memset(first, -1, sizeof(first)); m = 0; } void add_Edge(int u, int v, Type cap, Type cost) { edges[m] = Edge(u, v, cap, 0, cost); next[m] = first[u]; first[u] = m++; edges[m] = Edge(v, u, 0, 0, -cost); next[m] = first[v]; first[v] = m++; } bool bellmanford(int s, int t, Type &flow, Type &cost) { for (int i = 0; i < n; i++) d[i] = INF; memset(inq, false, sizeof(inq)); d[s] = 0; inq[s] = true; p[s] = s; a[s] = INF; queue<int> Q; Q.push(s); while (!Q.empty()) { int u = Q.front(); Q.pop(); inq[u] = false; for (int i = first[u]; i != -1; i = next[i]) { Edge& e = edges[i]; if (e.cap > e.flow && d[e.v] > d[u] + e.cost) { d[e.v] = d[u] + e.cost; p[e.v] = i; a[e.v] = min(a[u], e.cap - e.flow); if (!inq[e.v]) {Q.push(e.v); inq[e.v] = true;} } } } if (d[t] == INF) return false; flow += a[t]; cost += d[t] * a[t]; int u = t; while (u != s) { edges[p[u]].flow += a[t]; edges[p[u]^1].flow -= a[t]; u = edges[p[u]].u; } return true; } Type Mincost(int s, int t) { Type flow = 0, cost = 0; while (bellmanford(s, t, flow, cost)); return cost; } } gao;
一类K覆盖问题:
这类问题一般表现为,一个区间或者一些点。每一个能够最多被覆盖k次。然后有一些特殊的边能够走,可是仅仅能走一次,这时候要求k覆盖后的最大权值
事实上就是费用流。建边把特殊边建起来,相应相应费用,然后其它边直接相连,费用为0。注意因为是要求最大代价,而算法是求最小费用。事实上和KM匹配求最小一样的思路。把边权弄成负数,跑一下就可以
网络流的一些特殊问题
上下界网络流:
无源无汇有上下界最大流:
这个要依据流量平衡来搞。建图先把边容量定成上限up - 下限down。然后每个点,记录下流入流量和流出流量,然后设一个超级源s,超级汇t。s连接流量正的点。流量负的点连向t,然后跑最大流,跑完之后假设从s流出的流量都是满流,就是有解,每个边的真实流量就为当前边流量。加上原来的下限
有源有汇有上下界最大流:
建图方法一致,只是要多连上一条t->s容量为INF的边,这样跑一下最大流,t->s的流量就是答案
有源有汇有上下界最小流:
也是一样,只是t->s先不连,先求一次最大流,然后在连t->s,在做一次最大流把残余流量充分利用,然后t->s的流量就是答案
分层网络流:
这类题,以时间为单位。这样对于每一个时间点就要建一层结点。时间上限不是非常大的话,就能够每多一个时间点。就多一层结点,在原来的图上继续增广
混合图找欧拉回路:
欧拉回路入度等于出度。然后无向图先随意定向,然后记录每一个点的度数和。度数和 / 2就是须要调整的边数,然后把源点连向正的,负的连向汇点。然后中间的边就是连无向边,由于仅仅有无向边能够调整。然后跑一下最大流就可以
添加哪些边会使得最大流添加:
这类问题事实上就是对于满流的边,假设左边源点到他和他到汇点,能有一个残量网络,这条边就是能够添加的,利用两个dfs,分别从源点汇点出发就可以
最大密度子图:
先要记录下每一个结点的度数
利用二分搜索来搜索答案g,然后依据这个建图推断,推断的方式为:
源点与原图中每个点连一条容量为m的边。
原图中每个点与汇点连一条容量为m+2*g-度数的边,再将原图中的无向边拆成两条有向边,容量都设为1.然后对此图求最大流,最后将(n*m-maxflow)/2 与0比較大小,假设它大于0。l = g,否则r = g
POJ上的题目:
POJ 1698 Alice‘s Chance 最大流+拆点
POJ 2112 Optimal Milking 二分+最大流
POJ 2455 Secret Milking Machine 二分+最大流
POJ 1149 PIGS 最大流(建模是关键)
POJ 2135 Farm Tour 费用流
POJ 2516 Minimum Cost 费用流(注意每种互不影响物品分开讨论)
POJ 3281 Dining 最大流+建模
POJ 3469 Dual Core CPU 最小割
POJ 3680 Intervals k覆盖问题
POJ 3762 The Bonus Salary! k覆盖问题
POJ 2987 Firing 最大权闭合
POJ 1637 Sightseeing tour 混合图欧拉回路
POJ 3422 Kaka‘s Matrix Travels 转化为k覆盖问题
POJ 3189 Steady Cow Assignment 这样的是一类问题(二分差值,枚举下界。利用最大流去推断)
POJ 3204 Ikki‘s Story I - Road Reconstruction 添加哪些边会使得最大流添加
HDU上的题目:
HDU 1532 Drainage Ditches 最大流模板题
HDU 3081 Marriage Match II 二分+最大流
HDU 3277 Marriage Match III 二分+最大流+拆点
HDU 3416 Marriage Match IV 最短路+最大流
HDU 3376 Matrix Again 拆点+费用流
HDU 3313 Key Vertex 在最短路基础上dfs
HDU 3338 Kakuro Extension 最大流+行列模型
HDU 1565 方格取数(1) 最大点权独立集
HDU 1569 方格取数(2) 同上
HDU 3035 War 平面图求最小割
HDU 3046 Pleasant sheep and big big wolf 最小割
HDU 3251 Being a Hero 最小割
HDU 1733 Escape 分层网络流
HDU 2883 kebab 最大流+建模
HDU 2732 Leapin‘ Lizards 拆点+最大流
HDU 3061 Battle 最大权闭合
HDU 3157 Crazy Circuits 有源汇上下界最大流
以上是关于图论网络流总结的主要内容,如果未能解决你的问题,请参考以下文章