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][ ...
随机推荐
- Rsync+inotify 数据同步应用指南
Rsync+Inotify-tools (1):Inotify-tools 只能记录下被监听的目录发生了变化(包括增加.删除.修改),并没有 把具体是哪个文件或者哪个目录发生了变化记录下来: (2): ...
- Java虚拟机——Class类文件结构
Class文件格式采用一种类似C语言结构体的结构来存储数据,这种数据结构只有两种数据类型:无符号数和表. 无符号数属于基本的数据类型,数据项的不同长度分别用u1, u2, u4, u8表示, ...
- spring mvc 和spring boot 中注解的使用
1 spring mvc和spring boot之间的关系 spring boot包含spring mvc.所以,spring mvc的注解在spring boot总都是可以用的吗? spring b ...
- [洛谷P1709] 隐藏的口令
问题描述 有时候程序员有很奇怪的方法来隐藏他们的口令.Binny会选择一个字符串S(由N个小写字母组成,5<=N<=5,000,000),然后他把S顺时针绕成一个圈,每次取一个做开头字母并 ...
- Jenkins镜像
https://mirrors.tuna.tsinghua.edu.cn/jenkins/updates/update-center.json
- 为应用程序池 ''DefaultAppPool'' 提供服务的进程意外终止。进程 ID 是 ''xxx''问题的解决方法
网上提供了很多办法,都未解决. 解决过程一波三折,依次用了下列方法: 1.解决办法 点击“开始”-“控制面板”-“管理工具”-“组件服务”-“计算机”-“我的电脑”-“DCOM”选项, 选择其下的“I ...
- vue项目中使用element的dialog中引入ztree却不能初始化解决办法
一开始我在 里边写的,发现获取不到,那么采用dialog自带的回调函数,窗口打开后opend进行处理, 结果:
- linux(centos6) 下安装 postgresql-9.3.1.tar.gz
目录 一. 环境 二.准备工作 三.先安装 make, gcc ,gcc-c++,readline-devel ,zlib-devel .如果已安装,可以忽略 四.开始安装 4.1 解压 tar -z ...
- python 日期相关
基本的日期与时间转换 问题 你需要执行简单的时间转换,比如天到秒,小时到分钟等的转换. 解决方案 为了执行不同时间单位的转换和计算,请使用 datetime 模块. 比如,为了表示一个时间段,可以创建 ...
- 不用print调试 xdebug ubuntu phpstorm 远程断点调试
即使这会写php也遵守zebra大人的指示:不用print调试!!!!----环境ok ---gan !!! w http://blog.csdn.net/ty_hf/article/details ...