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][ ...
随机推荐
- 初步理解React
1.组件化 在 MV* 架构出现之前,组件主要分为两种: 狭义上的组件,又称为 UI 组件,比如 Tabs 组件.Dropdown 组件.组件主要围绕在交互 动作上的抽象,针对这些交互动作,利用 Ja ...
- nodejs 更新代码自动刷新页面
安装第三方工具: nodemon npm install --global nodemon 安装完毕后使用: 之前使用: node xxx.js 改成 nodemon xxx.js 只要通过nodem ...
- Windows安装Scrapy(转)
转自: http://www.nnzhp.cn/archives/558 Scrapy是python开发的一个爬虫框架,如果你要学习它的话,可能第一步在安装的时候,就会遇到很多问题,因为Scrapy很 ...
- hdu4417 Super Mario (树状数组/分块/主席树)
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4417 题目大意:给定一个长度为n的序列,有m个询问,每次询问包含l,r,h,即询问区间[l,r]小于等 ...
- vertica copy
copy huimei.ken_copy from '/home/dbadmin/file.txt' delimiter ';'
- 18 StringBuilder类型有何作用
- webdriver显式和隐式等待、强制等待
implicitly_wait() 方法是隐式等待,用来设置超时,一般把implicitly_wait()方法调用在加载测试地址后,等待所测试的应用程序加载WebDriverWait() 是显式等待, ...
- linux运维、架构之路-Zabbix自动化
一.Zabbix自定义监控 web01客户端修改/etc/zabbix/zabbix_agentd.conf [root@m01 tools]# echo "UserParameter=lo ...
- 前端开发本地存储之cookie
1.cookie cookie是纯文本,没有可执行代码,是指某些网站为了辨别用户身份.进行 session 跟踪而储存在用户本地终端(浏览器)上的数据(通常经过加密).当用户访问了某个网站的时候,我们 ...
- BZOJ 1492: [NOI2007]货币兑换Cash 斜率优化 + splay动态维护凸包
Description 小Y最近在一家金券交易所工作.该金券交易所只发行交易两种金券:A纪念券(以下简称A券)和 B纪念券(以下 简称B券).每个持有金券的顾客都有一个自己的帐户.金券的数目可以是一个 ...