Tarjan&2-SAT 总结
\(Tarjan\)&\(2-SAT\)
标签: 知识点总结
安利XZYXZY
ps:里面的部分东西来自\(Anson\)和\(yler\)和\(XZY\)
阅读体验:https://zybuluo.com/Junlier/note/1293491
\(Tarjan\)大爷
前世没见过Tarjan这么牛逼的人
并且他还弄了好多别的东西。。。
留这么多东西给我们。。。爆炸
强连通分量&割点&割边&点双&边双
简介
在有向图G中,如果两个顶点vi,vj间(vi>vj)有一条从vi到vj的有向路径,同时还有一条从vj到vi的有向路径,则称两个顶点强连通(strongly connected)。如果有向图G的每两个顶点都强连通,称G是一个强连通图。有向图的极大强连通子图,称为强连通分量(strongly connected components)。
若一个无向图中的去掉任意一个节点(一条边)都不会改变此图的连通性,即不存在割点(桥),则称作点(边)双连通图。一个无向图中的每一个极大点(边)双连通子图称作此无向图的点(边)双连通分量。
一些板子
大道理就不讲了,别人讲的好得多
强连通分量
void Tarjan(int now)
{
dfn[now]=low[now]=++Dex;
in[now]=true,st[++top]=now;
for(int i=hd[now];i;i=ljl[i].nxt)
{
int qw=ljl[i].to;
if(!dfn[qw])Tarjan(qw),low[now]=min(low[now],low[qw]);
else if(in[qw])low[now]=min(low[now],dfn[qw]);
}
if(dfn[now]==low[now])
{
++color;
while(st[top+1]!=now)
{
col[st[top]]=color;
in[st[top]]=false,--top;
}
}
}
割边(桥)
为树边且连接的子树返祖不回来
int tarjan(int now,int fm)
{
low[now]=dfn[now]=++Dex;
for(int i=hd[now];i;i=ljl[i].nxt)
{
int qw=ljl[i].to;
if(qw==fm)continue;
if(!dfn[qw])
{
Tarjan(qw,now);
low[now]=min(low[now],low[qw]);
if(low[qw]>dfn[now])
Bridge.pk(mp(min(now,qw),max(now,qw)));
// push_back make_pair
}
else if(dfn[qw]<dfn[now])low[now]=min(low[now],dfn[qw]);
}
}
割点
- 为树根时:两个以上的子树就\(ok\)
- 不为树根时:子树返祖最多到自己
void Tarjan(int now,int rt)
{
int s=0;dfn[now]=low[now]=++Dex;
for(int i=hd[now];i;i=ljl[i].nxt)
{
int qw=ljl[i].to;
if(!dfn[qw])
{
Tarjan(qw,rt);low[now]=min(low[now],low[qw]);
if(now==rt)++s;
else if(low[qw]>=dfn[now])cut[now]=1;
}
else low[now]=min(low[now],dfn[qw]);
}
if(now==rt&&s>1)cut[now]=1;
}
点双
- 求割点
- 重新\(Dfs\)一遍图,强制不经过割点,栈里面就是了(要包含割点)
- 所以,一个割点会在多个点双里面
void Tarjan(int now,int fm)
{
int s=0;dfn[now]=low[now]=++Dex;
for(int i=hd[now];i;i=ljl[i].nxt)
{
int qw=ljl[i].to;if(qw==fm)continue;
if(!dfn[qw])
{
Tarjan(qw,now);s++;
tag[now]|=low[qw]>=dfn[now];
low[now]=min(low[now],low[qw]);
}
else low[now]=min(low[now],dfn[qw]);
}
if(!fm&&s==1)tag[now]=0;
}
边双
求出桥,然后重新Dfs一遍,强制不经过桥,所有的联通块都是边双。。。
\(Brg\)代表边是不是桥,\(col\)之类的就是边双染色了。。。
void Tarjan(int now,int fm)
{
dfn[now]=low[now]=++Dex;
for(int i=G1.hd[now];i;i=G1.ljl[i].nxt)
{
int qw=G1.ljl[i].to;
if(qw==fm)continue;
if(!dfn[qw])
{
Tarjan(qw,now);
low[now]=min(low[now],low[qw]);
if(low[qw]>dfn[now])Brg[i>>1]=1;
}
else low[now]=min(low[now],dfn[qw]);
}
}
void Dfs(int now,int Col)
{
col[now]=Col;
for(int i=G1.hd[now];i;i=G1.ljl[i].nxt)
{
int qw=G1.ljl[i].to;
if(!Brg[i>>1]&&!col[qw])Dfs(qw,Col);
}
}
题目
- [x] UOJ#67. 新年的毒瘤
- [x] P3225 [HNOI2012]矿场搭建
缩点(其实可以放一起)
简介
对于一些题目,我们可以在求出 强/点双/边双 连通分量后将每个东西(你懂的)缩成一个点,从而把图简化。有向图缩强连通分量后会变成一个DAG,边双缩点变成树,至于点双。。。需要用一种叫做圆方树的东西维护。
题目
- [x] P2403 [SDOI2010]所驼门王的宝藏
- [x] 洛谷 P1262 间谍网络
- [x] CJOJ P1851 免费航班
\(Tarjan\)求\(LCA\)
这是一个询问\(O(1)\)但是只能离线的求\(LCA\)的高科技
我们求\((p,q)\)的\(LCA\)把询问离线,在\(p,q\)上对询问挂链
扫一遍整棵树,一边回答
那么具体怎么回答的呢,维护一个并查集,表示已经完成的子树的最高祖先
这个具体来说就是\(fa[i]\)为\(i\)点在已经完成的树内的最高祖先,显然对于其他没有完成的点如果要求与\(i\)的\(LCA\)的话,就直接是\(fa[i]\)了是吧
反正很难懂,建议自己对这代码手玩,例题:洛谷P3379 【模板】最近公共祖先(LCA)
//你不觉得压行很美丽吗QwQ
#include<bits/stdc++.h>
#define il inline
#define rg register
#define ldb double
#define lst long long
#define rgt register int
#define N 500050
#define pb push_back
#define qw ljl[i].to
#define ot Pm[now][i].to
using namespace std;
const int Inf=1e9;
il int MAX(rgt x,rgt y){return x>y?x:y;}
il int MIN(rgt x,rgt y){return x<y?x:y;}
il int read()
{
int s=0,m=0;char ch=getchar();
while(!isdigit(ch)){if(ch=='-')m=1;ch=getchar();}
while( isdigit(ch))s=(s<<3)+(s<<1)+(ch^48),ch=getchar();
return m?-s:s;
}
int n,m,Rt,cnt;
int hd[N],fa[N],vis[N];
struct NODE{int to,id;};
vector<NODE> Pm[N];int ans[N];
struct EDGE{int to,nxt;}ljl[N<<1];
int Find_fa(rgt k){return fa[k]==k?k:fa[k]=Find_fa(fa[k]);}
il void Add(rgt p,rgt q){ljl[++cnt]=(EDGE){q,hd[p]},hd[p]=cnt;}
void Answer(rgt now)
{
for(rgt i=0,Sz=Pm[now].size();i<Sz;++i)
if(vis[ot])ans[Pm[now][i].id]=Find_fa(ot);
}
void Dfs(rgt now)
{
vis[now]=1,Answer(now);
for(rgt i=hd[now];i;i=ljl[i].nxt)
if(!vis[qw])Dfs(qw),fa[qw]=now;
}
int main()
{
n=read(),m=read(),Rt=read();
for(rgt i=1;i<=n;++i)fa[i]=i;
for(rgt i=1,p,q;i<n;++i)
p=read(),q=read(),Add(p,q),Add(q,p);
for(rgt i=1,u,v;i<=m;++i){
u=read(),v=read();
Pm[u].pb((NODE){v,i}),Pm[v].pb((NODE){u,i});
}Dfs(Rt);for(rgt i=1;i<=m;++i)printf("%d\n",ans[i]);
return 0;
}
2-SAT
简介
每种物品有选或者不选两种状态,有些限制条件形如
选了则必须选,和不能同时选,必须选等等
把逻辑限制关系变成连边
a->b表示如果成立那么一定成立
这个要求你理解逆否命题
逆否命题,举个例子,选必须选,那么我选了就不能选,选就必须选
由于逆否命题产生的对称性使得问题得以在时间求解
具体来说要求同时连接x->y y'->x'
这样跑一遍缩点后如果统一物品的两种状态在同一个边双连通分量中就无解
否则可以输出方案,具体来说是每个点选择缩成的超级点中编号最小的那个(也就是反图拓扑序最小的那个)
题目
- [ ] [POI2001]和平委员会
- [ ] [JSOI2010]满汉全席
- [ ] [UOJ210]寻找罪犯
- [ ] [NOI2017]游戏
- [ ] [HNOI2010]平面图判定
- [ ] [POI2010]KOL-Railway
- [ ] 奶牛议会
综合题目?
- [ ] P3132 [USACO16JAN]愤怒的奶牛Angry Cows
- [ ] P2941 [USACO09FEB]环绕岛屿Surround the Islands
- [ ] P2746 [USACO5.3]校园网Network of Schools
- [ ] P3398 仓鼠找sugar
- [ ] P3469 [POI2008]BLO-Blockade
- [ ] P3436 [POI2006]PRO-Professor Szu POI
- [ ] P3119 [USACO15JAN]草鉴定Grass Cownoisseur
- [ ] P2321 [HNOI2006]潘多拉的宝盒
- [ ] P3627 [APIO2009]抢掠计划
Tarjan&2-SAT 总结的更多相关文章
- 学习笔记(two sat)
关于two sat算法 两篇很好的论文由对称性解2-SAT问题(伍昱), 赵爽 2-sat解法浅析(pdf). 一些题目的题解 poj 3207 poj 3678 poj 3683 poj 3648 ...
- HIT 1917 2—SAT
题目大意:一国有n个党派,每个党派在议会中都有2个代表, 现要组建和平委员会,要从每个党派在议会的代表中选出1人,一共n人组成和平委员会. 已知有一些代表之间存在仇恨,也就是说他们不能同时被选为和平委 ...
- HDU4738 tarjan割边|割边、割点模板
题目:http://acm.hdu.edu.cn/showproblem.php?pid=4738 坑点: 处理重边 图可能不连通,要输出0 若求出的结果是0,则要输出1,因为最少要派一个人 #inc ...
- bzoj 1179[Apio2009]Atm (tarjan+spfa)
题目 输入 第一行包含两个整数N.M.N表示路口的个数,M表示道路条数.接下来M行,每行两个整数,这两个整数都在1到N之间,第i+1行的两个整数表示第i条道路的起点和终点的路口编号.接下来N行,每行一 ...
- tarjan讲解(用codevs1332(tarjan的裸题)讲解)
主要借助这道比较裸的题来讲一下tarjan这种算法 tarjan是一种求解有向图强连通分量的线性时间的算法.(用dfs来实现) 如果两个顶点可以相互通达,则称两个顶点强连通.如果有向图G的每两个顶点都 ...
- NOIP2009最优贸易[spfa变形|tarjan 缩点 DP]
题目描述 C 国有 n 个大城市和 m 条道路,每条道路连接这 n 个城市中的某两个城市.任意两个 城市之间最多只有一条道路直接相连.这 m 条道路中有一部分为单向通行的道路,一部分 为双向通行的道路 ...
- Tarjan
//求强连通分量 void uni(int x,int y){ if (rank[x]<rank[y]){ fa[x]=y; size[y]+=size[x]; }else{ rank[x]+= ...
- 【UOJ#67】新年的毒瘤 Tarjan 割点
#67. 新年的毒瘤 UOJ直接黏贴会炸... 还是戳这里吧: http://uoj.ac/problem/67#tab-statement Solution 看到这题的标签就进来看了一眼. 想 ...
- 【Codefoces487E/UOJ#30】Tourists Tarjan 点双连通分量 + 树链剖分
E. Tourists time limit per test: 2 seconds memory limit per test: 256 megabytes input: standard inpu ...
- 【BZOJ-1123】BLO Tarjan 点双连通分量
1123: [POI2008]BLO Time Limit: 10 Sec Memory Limit: 162 MBSubmit: 970 Solved: 408[Submit][Status][ ...
随机推荐
- Windows 进入上帝模式窗口
Win10上帝模式如何启用? 默认情况下,Win10的上帝模式是隐藏的,如果要开启的话,操作步骤也非常简单,下面就介绍两种方法. 方法一.直接运行命令行 1.使用[Win + R ]快捷键打开“运行” ...
- 树——minimum-depth-of-binary-tree(二叉树的最小深度)
问题: Given a binary tree, find its minimum depth.The minimum depth is the number of nodes along the s ...
- 调整notepad++的行距的方法
notepad++是一款免费开源的文本编辑器,在windows平台上表现非常好,可以自定义的地方多,还支持主题导入,导出和切换,对各种语言的语法高亮支持也是在各大文本编辑器中名列前茅,插件库的内容也非 ...
- 使用Node,Vue和ElasticSearch构建实时搜索引擎
(译者注:相关阅读:node.js,vue.js,Elasticsearch) 介绍 Elasticsearch是一个分布式的RESTful搜索和分析引擎,能够解决越来越多的用例. Elasticse ...
- django之创建子应用
一:子应用 Django的视图编写是放在子应用中的.类似于flask中的视图. 二:创建子应用 例如:在刚才的dj_study项目中,创建一个名字为user的子应用(目录):注意是第一级的dj_stu ...
- 【説明する】STL
作为C++标准不可缺少的一部分,STL应该是渗透在C++程序的角角落落里的. STL不是实验室里的宠儿,也不是程序员桌上的摆设,她的激动人心并非昙花一现. 所以今天要整理的东西就是STL!(orz 杨 ...
- 检测代理IP匿名程度的方法,很实用
做网络的基本都知道代理,这个是肯定的,不管是用花刺还是猎手的网页代理,还是直接VPN的通道代理,代理有着不用说大家也知道的重要性.不管是做CPA还是做点击亦或者投票,代理都能帮我们一下,虽然帮的忙不大 ...
- scrapy之Request对象
我们在使用scrapy框架的时候,会经常疑惑,数据流是怎么样在各个组件中间传递的.最近经常用scrapy+selenium爬取淘宝,又因为今天周五心情好,本宝宝决定梳理一下这方面知识. scrapy中 ...
- 关于C(n,m) 的奇偶 ,与C(n,0),C(n,1),C(n,2)…C(n,n).当中有多少个奇数
(n & m) == m 为奇数 C(n,0),C(n,1),C(n,2)…C(n,n).当中有多少个奇数 第一种想法是Lucas定理推导,我们分析一下 C(n,m)%2,那么由lucas定 ...
- 专人写接口+模型,专人写业务逻辑---interface_model -- business logical
专人写接口+模型,专人写业务逻辑---interface_model -- business logical 0-控制台脚本重构为“面向接口编程”:1-仓库类通过__constru方法,来实现一处实例 ...