8.22上课感悟

6 篇文章 0 订阅
2 篇文章 0 订阅

今天我自己主要把昨天网络流的东西再做一做,下午讲课讲  2SAT 问题
我打算将感悟分成两半,第一部分主要写写昨天没写完的Dinic算法,第二部分主要讲讲  2SAT 和相关的题目

Part1

EK算法应该还记得吧,时间复杂度比较高
Dinic算法基本上可以说是对EK算法的一个优化吧
在讲Dinic算法之前,先说一下最短增广路算法

概念

网络的层次:对于点  i ,记  li 表示这个点的层数,那么,  li= 从源点  S 到点  i 最少经过的边数
特别地,  lS=0
对网络分层就是将网络中所有点的层数求出
层次网络:对于其中任意一条弧  (u,v) ,都满足  lu+1=lv

思想

每一次在层次网络中找到一条含弧数较少的增广路进行增广
步骤:
1.初始化
2.构造层次网络,看汇点是否在网络中。如果汇点在网络中,在层次网络中一直增广,直到找不到增广路。增广后,在层次网络中去掉饱和的弧。否则结束。
增广到边  (u,v) 的时候,如果满足  lu+1=lv ,就增广这条边

复杂度

建立层次网络需要用到bfs,最多会出现  O(n) 个层次网络,bfs复杂度为  O(m) ,建立复杂度为  O(nm)
每条边只会被增广一次,所以最多会增广  m 次。用bfs来进行增广,时间为  O(m) 。调整每条边的流量需要消耗  O(n) 的时间。增广复杂度为  O(m(n+m))=O(m2)
总复杂度为  O(nm2)

这个算法的时间复杂度并没有多大的保证,一不小心就会T,建议大家还是用下面要说的Dinic算法

Dinic算法

为什么前面的算法时间复杂度特别高?因为每一次只增广一次,太浪费了
所以Dinic算法就用dfs多次增广,效率就自然上来了
算法的大致流程:
前两步同上面算法
3.用dfs进行增广
时间复杂度分析:
建立层次网络依然是  O(nm)
修改增广路最多增广  m 次,每一次调整流量时间为  O(n) ,增广后后退的时间也为  O(n)
增广路长度最大为  n ,每一次增广后要删除一条路径的最后一个点,最坏后退  n
所以dfs的时候复杂度为  O(nm)
所以最后总时间复杂度为  O(n2m)

相对于前面的算法显然要好了很多啊
发一下Dinic的代码

bool bfs(int s,int t){//bfs为寻找增广路的过程,true为存在增广路
    memset(l,0,sizeof(l));l[s]=1;//l数组表示每个点的层数
    queue<int> q;q.push(s);
    while(!q.empty()){
        int x=q.front();q.pop();
        if(x==t) return true;//如果遇到汇点,说明存在增广路径
        for(int p=e[x].next;p;p=e[p].next){
            int k=e[p].num,c=e[p].c;
            if(!l[k]&&c){
                l[k]=l[x]+1;
                q.push(k);
            }
        }
    }
    return false;
}
int dfs(int s,int t,int maxf){//maxf表示当前的流量上界是多少
    if(s==t) return maxf;
    int ret=0;//ret表示这个层次网络的最大流
    for(int p=e[s].next;p;p=e[p].next){
        int k=e[p].num,c=e[p].c;
        if(l[s]+1==l[k]&&c){
            int Min=min(maxf-ret,c);//取min应该比较好理解,因为小的可以流到大的,但大的不一定能流到小的
            c=dfs(k,t,Min);
            e[p].c-=c;e[p^1].c+=c;
            ret+=c;
            if(ret==maxf) return ret;//如果漫流,就不可能更多了,直接退出
        }
    }
    return ret;
}
int Dinic(int s,int t){
    int maxflow=0;
    while(bfs(s,t)) maxflow+=dfs(s,t,INT_MAX);//求解最大流
    return maxflow;
}

代码也比较简短,掌握了就会好很多
我曾经提到过二分图最大匹配可以用网络流做,时间复杂度比匈牙利要好得多
其实Dinic复杂度比  O(n2m) 要低,这是上界,并且很松
但匈牙利唯一优势在于可以求出字典序最小的最大匹配
曾经有人用Dinic跑  n=105,m=106 的最大流,就是过了(数据随机)
说明这个算法的效率还是很高的,要好好写
最大流一般都会用Dinic来写

Part2

下面我们换个思路,讲讲  2SAT 问题

概念

 SAT 问题:一些由布尔值组成的关系的集合
 2SAT 问题:由两个布尔值组成的关系的集合
给你一堆关系,最后问你能否满足所有的关系??
来个例题看看,顺便讲一下这类问题的方法

例题

和平委员会(Poi 0106)
某国有  n 个党派,每个党派有2个代表
要建立一个和平委员会,并要满足下面两个条件:
1.每个党派只有一个代表
2.不能出现两个代表不和的情况(不和的关系告诉你)
 i 个党派的两个代表编号分别为  2i+1  2(i+1)
问能否使每个党派都有代表在委员会里?
求出方案(其实不重要)
 n8000m20000

做法

我们先假设第  i 个党派的一个代表为  i ,另一个为  i
如果出现某两个代表  i  j 不和,那么选择了  i ,就要选择  j ;选择了  j ,就要选择  i
那么我们可以连边  (i,j)  (j,i)
这两条边对称(很关键)
举个例子
假设有4个党派,不和关系为:1和4,2和3,3和7
考虑下面的构图:
这里写图片描述
假设先选1,3,8必须选,2,4,7不能选,5,6随意
这样建图就比较巧妙啦
为什么会出现矛盾呢?(这个点必须选但是有不能选……好尴尬
那么我们就会有一个比较暴力的做法:
枚举每一对没有定下来怎么选的  (i,i) ,任选一个,开始推导其他的种种关系
如果都出现矛盾,那么就无解
正确性?前面的决策并不会影响  (i,i)
时间复杂度? 最坏  O(nm)
有没有优化?
注意,  2SAT 问题主要的优化是看它的对称性
显然暴力对于对称性不怎么会用……
对于上面的例子,发现1,3构成一个环,2,4构成一个环
说明1,3怎么取是固定的,2,4怎么取也是固定的
说明一个环里怎么取肯定是固定的
可以用tarjan算法缩点,将强连通分量缩成一个点,并标记好原图中每一个点属于哪一个强联通分量,建立一个新图
所以新图就变成了一个DAG(有向无环图)
如果出现某一对  (i,i) 属于同一个点,肯定无解
否则用拓扑排序自底向上来求,肯定存在可行解
正确性证明?
显然,原图是具有对称传递性的(  i ->  k ,那么  k ->  i “->”表示传递的关系)
根据上面的对称传递性,环是对称的
新图也同样存在对称性
定义  Si 表示第  i 个环
对于任意一对  (Si,Si) ,  Si 的后代节点和  Si 的前代祖先也不能选
如果选择了  Si ,那么对于所有边  (Si,Sj)  Sj 必须选
因为新图依然具有对称性,那么  Si 不可选(  Si 表示  Si 的对称点)。所以  Si 的前代祖先也不能选,假设我们删除了这些点
因为前代祖先的某种对称关系(上面提到了),所以这样删除并没有矛盾
所以一定可以构造出一种可行解(证毕)

相关细节:拓扑排序的时候,因为新图变成了两个部分,并且对称,所以要两边同时做
时间复杂度?  O(m)
 2SAT 问题必须要满足对称性(无向图显然没有问题,有向图必须满足对称)

看一道比较高端的  2SAT

高端例题

游戏(NOI2017 day2T1)
有一个字符串长度为  n ,每一位有四种字符(分别为小写字母a,b,c,x)。现在每一位可以放大写字母A,B,C。在某位字符为x的位置上三种都能放,其他的不能出现大小写对应的情况(比如a号位不能选A)
还有  m 个特殊的约束条件,形如  (i,hi,j,hj) 。表示如果在  i 号位选择  hi 字符,那么  j 号位必须选择  hj 字符
求出一种合法的方案,如果无解,输出-1
如果有多组解,输出任意一种
 n5104,m105,d=|x|8

 2SAT 模型?
一看难道不是  3SAT 么,NP问题……
出题人出错了????
因为每一位只能选两种,所以不可能是  3SAT 问题
图满足对称性???
假设字符串为  abc ,约束条件为  (2,A,3,B)
那么二号位的A连上三号位的B(有向边)
因为每一位都要取,所以三号位的A连上二号位的C
所以满足对称性
如果  d=0 ?? 直接  2SAT 问题即可(tarjan缩点+拓扑排序)
如果  d>0 ??
时间复杂度  O(3d(n+m)) ??
这显然T飞了吧……
如何优化????
考虑某一个点限制为不能取A,那么就可以取B,C。同理,如果不能取B,那么只能取A,C
如果在不能取A的情况下没有可行解,那么就不能取B,C
再看能不能取A,即看不能取B的情况
若没有可行解,说明A也不能取
所以无解,只需枚举两种即可
时间复杂度  O(2d(n+m))

我们就成功地解决了一个NOI问题啦!!!
激动的心情不禁溢于言表……

当时讲题人说如果这题考场上A掉,笔试满分,其他题暴力基本就可以拿Cu了
表示我连胸牌都没有,还说啥……

 2SAT 的具体代码我还没有写,最近有时间会写写
代码可能比较丑陋,就不敢发上来了……
讲题人说  2SAT 问题比较明显,基本想到了对称性就可以A掉了……
表示我这种连胸牌选手都算不上的人能信么……

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值