【算法简介】
网络流是个好东西
主要掌握dinic的写法(最好是带上各种优化的)后,就是各种建图的套路了
直接放个dinic的板子
const ll inf=1e17;
int head[maxn],tot=1,cur[maxn];
struct edge
{
int to,nxt;
ll v;
}e[maxm<<1];
void add(int x,int y,ll z)
{
e[++tot].to=y; e[tot].nxt=head[x]; e[tot].v=z; head[x]=tot;
e[++tot].to=x; e[tot].nxt=head[y]; e[tot].v=0; head[y]=tot;
}
int dep[maxn];
bool bfs()
{
for(int i=S;i<=T;i++)
cur[i]=head[i],dep[i]=-1;
queue <int> q;
dep[S]=0;
q.push(S);
while(!q.empty())
{
int u=q.front(); q.pop();
for(int i=head[u];i;i=e[i].nxt)
{
int to=e[i].to;
if(dep[to]!=-1 || !e[i].v) continue;
q.push(to);
dep[to]=dep[u]+1;
}
}
return (dep[T]!=-1);
}
ll dfs(int u,ll flow)
{
if(u==T) return flow;
ll res=0;
for(int &i=cur[u];i;i=e[i].nxt)
{
int to=e[i].to;
if(dep[to]!=dep[u]+1 || e[i].v<=0) continue;
ll tmp=dfs(to,min(e[i].v,flow));
flow-=tmp; res+=tmp;
e[i].v-=tmp; e[i^1].v+=tmp;
}
if(!res) dep[u]=-1;
return res;
}
ll dinic()
{
ll ans=0;
while(bfs())
{
ans+=dfs(S,inf);
}
return ans;
}
下面就是各种的建图分析了
【1.黑白染色】
这是一类经典的方法,对于点坐标(i,j),如果按照(i+j)%2的答案分成颜色,也就能得到一个类似这样的图:
这样一张图可以很好的一些相邻的节点的问题,因为相邻节点被分到了两个不同的集合中
【例题1】P3355 骑士共存问题
【习题1.1】P2774 方格取数问题
【习题1.2】P4474 王者之剑
【2.二者选其一】
这类问题一般都是选择放在A/B,或者选/不选,而且点与点之间可能有一些相互的影响
再考虑影响的时候,我们可以建一些边权为inf的边,表示我们割不动的边,以此来限制一些条件
常见的建模方式1:
源点到 i 建边权为选A的价值,i 到汇点建边权为B的价值
然后求最小割,用总权值-最小割的值,也就是割掉哪个就不选哪侧,然后再特殊考虑点与点之间的作用即可
【例题2.1】BZOJ2039. [2009国家集训队]employ人员雇佣
【习题2.1】P4313 文理分科
【习题2.2】P4210 土地划分
【习题2.3】P3973 [TJOI2015]线性代数
常见的建模方式2:
把一个点 i 拆成两个, i 和 i' ,S->i 和 i'连边权为价值的边,然后 i 和 j' 之间连互相的影响
然后求最小割,用总权值-最小割/2的值
【例题2.2】BZOJ3158. 千钧一发
【习题2.2】BZOJ3275. Number
【3.条件依赖】
个人理解这是有类别/归属的一种问题,建图也比较灵活
【例题3】P2763 试题库问题
【4.线段树优化建图】
它们之间都有共通点,就是对某段连续的区间加边,那么就可能可以用线段树优化。
注意到线段树每一个节点就代表一段连续的区间,这样对某一段区间的点加边就可以变成对线段树上的某些点加边了。
【例题4】BZOJ3218. a + b Problem
【习题4.1】BZOJ3681. Arietta
【5.特殊类建图】
【LIS 例题5.1】 P2766 最长不下降子序列问题
【LIS+贪心退流】P3308 [SDOI2014]LIS
【混合图欧拉回路】P3511 [POI2010]MOS-Bridges
【最大权闭合子图】P2762 太空飞行计划问题
【6.最小割树】
最小割树用于解决无向图上任意两点间的最小割
实际上思路很简单,每次随意选择一个S,T,然后求出最小割
在最小割树上建立S,T边权为mincut的边,然后把连着S和T的分成两个集合继续递归建最小割树
这样走(n-1)次网络流,就建立了最小割树
对于u,v的最小割,我们所求就是最小割树上两点间路径的边权最小值,用倍增维护一下即可解决
【例题6】P4897 【模板】最小割树(Gomory-Hu Tree)
【习题6.1】P3329 [ZJOI2011]最小割
【习题6.2】BZOJ3345. Pku2914 Minimum Cut
【习题6.3】P4123 [CQOI2016]不同的最小割
【习题6.4】CF343E Pumping Stations
【7.费用流】
费用流指的是在保证最大流的情况下,最小的费用
所以这类题型一般都可以转换成在保证...的条件下,....最..的方案
然后我们可以用spfa代替bfs,然后用EK算法增广即可
【例题7.1】P3381 【模板】最小费用最大流
【习题7.1】P1251 餐巾计划问题
【习题7.2 平方拆边 费用提前计算】P4307 [JSOI2009]球队收益 / 球队预算
【习题7.3 动态加边】P2050 [NOI2012] 美食节
【习题7.5 平方拆边 贪心增广】P4209 学习小组
【习题7.4 消圈】POJ2175.Evacuation Plan
【习题7.6 奇怪建图】P3980 [NOI2008] 志愿者招募
【习题7.7 建图+特殊增广】P4068 [SDOI2016]数字配对