网络流总结

【算法简介】

网络流是个好东西

主要掌握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 骑士共存问题 

sol.

【习题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]数字配对

 

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值