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][ ...
随机推荐
- 行人重识别(ReID) ——数据集描述 DukeMTMC-reID
数据集简介 DukeMTMC 数据集是一个大规模标记的多目标多摄像机行人跟踪数据集.它提供了一个由 8 个同步摄像机记录的新型大型高清视频数据集,具有 7,000 多个单摄像机轨迹和超过 2,700 ...
- layui隐藏表格列
根据需求我们需要展示某些数据,但有的时候这些数据又不该展示出来,比如不同角色看到不同数据,这个时候就会需要隐藏些数据了 我们需要在表格完成的回调进行处理 done: function (res, cu ...
- Unity 官网无法访问|国外网站访问过慢|国外网站访问加速器
目录 1. 文档地址 2. 按 3. 工具下载地址 1. 文档地址 GitHub博客 https://coco5666.github.io/blog/articles/20190704-01/ 2. ...
- 237-基于Xilinx Kintex-7 XC7K325T 的FMC/千兆以太网/SATA/四路光纤数据转发卡
基于Xilinx Kintex-7 XC7K325T 的FMC/千兆以太网/SATA/四路光纤数据转发卡 一. 板卡概述 本板卡基于Xilinx公司的FPGAXC7K325T-2FFG900 芯片, ...
- 前端每日实战:91# 视频演示如何用纯 CSS 创作一个行驶中的火车 loader
效果预览 按下右侧的"点击预览"按钮可以在当前页面预览,点击链接可以全屏预览. https://codepen.io/comehope/pen/RBLWzJ 可交互视频 此视频是可 ...
- 【leetcode】1089. Duplicate Zeros
题目如下: Given a fixed length array arr of integers, duplicate each occurrence of zero, shifting the re ...
- FPGA资源平民化的新晋- F9 技术解析
FPGA (现场可编程门阵列)由于其硬件并行加速能力和可编程特性,在传统通信领域和IC设计领域大放异彩.一路走来,FPGA并非一个新兴的硬件器件,由于其开发门槛过高,硬件加速算法的发布和部署保护要求非 ...
- 【转】通过Nginx部署Django
https://www.cnblogs.com/frchen/p/5709533.html Django的部署可以有很多方式,采用nginx+uwsgi的方式是其中比较常见的一种方式. 在这种方式中, ...
- 20180708-Java基本数据类型
public class PrimitiveTypeTest{ public static void main(String[] args){ //byte System.out.println(&q ...
- Linux负载均衡软件LVS
linux下的开源负载均衡软件LVS的安装.配置和使用.LVS是一个中国人创建和开发的开放源码项目,利用LVS可以构建高可用.高可靠的负载均衡集群,因此,利用Linux+LVS不但可以假设高性能的负载 ...