首页 > 其他分享 >Tarjan

Tarjan

时间:2024-09-15 20:35:19浏览次数:10  
标签:Tarjan cur int id dfn low 节点

P3388 【模板】割点(割顶)

1、注意在遍历时要储存根节点编号,判断时需要特判根节点

#include<bits/stdc++.h>
using namespace std;
const int N = 1e5+10;   
int n,m,r;
int dn,dfn[N],low[N],cnt,buc[N];
vector<int> e[N];
void dfs(int id){
	//标记时间戳 
	dfn[id] = low[id] = ++dn;
	int son = 0;
	//遍历该点相邻点 
	for(int it : e[id]){
		//如果没有被遍历 
		if(!dfn[it]){
			//其子节点加一 
			son++;
			//遍历当前节点 
			dfs(it);
			//进行更新 
			low[id] = min(low[id],low[it]);
			//若id的子节点不能够通过其他路径走到比id时间戳更小的点 并且 id不为根节点 
			//id就为割点 
			if(low[it] >= dfn[id] && id != r){
				//割点数量加一 
				cnt += !buc[id];
				//将id标记为割点 
				buc[id] = 1;
			}			
		}else{
			//更新id_low为其邻点的最小时间戳 
			//得到通过id点能够到达的最小值 
			low[id] = min(low[id],dfn[it]);
		}
	}
	//如果id是根节点,但其有两个以上的子树,那么id为割点 
	if(son >= 2 && id == r){
		//更新,标记 
		cnt += !buc[id];
		buc[id] = 1;
	}
}
int main(){
	cin>>n>>m;
	//邻接表存储连点 
	for(int i = 1; i <= m; ++i){
		int u,v;
		cin>>u>>v;
		e[u].push_back(v);
		e[v].push_back(u);
	}
	//遍历dfs 
	for(int i = 1; i <= n; ++i){
		//没有被遍历 
		if(!dfn[i]){
			//初始化顶点 
			r = i;
			dfs(i);
		}
	}
	cout<<cnt<<endl;
	for(int i = 1; i <= n; ++i){
		if(buc[i]){
			cout<<i<<" ";
		}
	}
	return 0;
} 

洛谷 P1656 炸铁路

读图,邻接表存图,tarjan求割边(桥),排序,输出

注意父亲节点的判断,如果两点之间有重边的情况需要注意

如果在第一次之外还回到了父亲结点(说明可能有重边),则按像计算儿子结点的方法一样用父亲结点的值更新当前结点的值。

#include<bits/stdc++.h>
using namespace std;
const int MAXN = 10010;
int n, m, x, y, idx, dfn[MAXN], low[MAXN], ans,a;
//dfn储存固定时间戳, low储存其出点能够到达的最小时间戳
vector<int> G[MAXN];//使用邻接表存图 
struct Edge{int from, to;} edge[MAXN];//题目要求,a < b 
bool cmp(const Edge a, const Edge b){if(a.from != b.from)return a.from < b.from; return a.to < b.to;}//题目要求排序 
inline void add_edge(int x, int y){edge[ans].from = min(x, y); edge[ans].to = max(x, y); ans++;}//在答案中加入一条边 
void dfs(int cur, int fa){//cur当前节点, fa 为其父亲节点 
	int child;
	dfn[cur] = ++idx;// 计算当前节点的时间戳 
	low[cur] = dfn[cur];//初始化 当前可以访问到的最早时间戳肯定是自己的时间戳 
	bool vis = false;//防止在有重边时会出错
	for(int i = 0; i < G[cur].size(); ++i){//遍历它的所有出点 
		child = G[cur][i];//取出出点 
		//如果这个节点被访问过 
		if(dfn[child]){
			if(child == fa && !vis) vis = true;//如果是父亲节点 且是第一次访问不做任何操作 
			else low[cur] = min(low[cur], dfn[child]);//如果访问到了不是父亲节点的节点 更新low值 
			//如果在第一次之外还回到了父亲结点,则按像计算儿子结点的方法一样用父亲结点的值更新当前结点的值。
		}
		//如果这个节点之前没有被访问过 
		if(!dfn[child]){
			dfs(child, cur);//进行dfs 
			if(dfn[cur] < low[child]) add_edge(cur, child);//如果满足条件(当前节点向下走无法回到之上的节点),
			//说明当边是割边 将其加入答案之中 
			low[cur] = min(low[cur], low[child]);
			//更新当前节点的low值 
		}
	}
}
int main(){
	cin >> n >> m;
	for(int i = 0; i < m; ++i) cin >> x >> y,G[x].push_back(y),G[y].push_back(x);
	for(int i = 1; i <= n; ++i) if(!dfn[i]) dfs(i, i);//图可能不连通, 初始时将自己的父亲节点初始化为自己,不会出错 
	sort(edge, edge + ans, cmp);//将答案进行排序 
	for(int i = 0; i < ans; ++i) cout << edge[i].from <<" "<< edge[i].to << endl;//输出 
	return 0;
} 

标签:Tarjan,cur,int,id,dfn,low,节点
From: https://www.cnblogs.com/lyx9785/p/18415593

相关文章

  • tarjan里的定义
     强连通分量-OIWiki(oi-wiki.org)   从以u为根的子树中的任意点出发。单次到达(从这个点指向某个点,有一条边)的这些点中的dfn的最小值 以v为根的子树,包含在以u为根的子树中,low[v]所用的子节点,一定也可以被low[u],这个点一定在以u为根的子树里,所以用low[v]  从......
  • 一文轻松搞定 tarjan 算法(二)(附带 tarjan 题单)
    完结篇:tarjan求割点、点双连通分量、割边(桥)(附40道很好的tarjan题目)。上一篇(tarjan求强连通分量,缩点,求边双)tarjan求割点还是求强联通分量的大致思路捏.算法思路:我们把图中的点分为两种:每一个联通子图搜索开始的根节点和其他点。判断是不是割点的方式如下:对于根......
  • tarjan—算法的神(一)cw
    本篇包含tarjan求强连通分量、边双连通分量、割点部分,tarjan求点双连通分量、桥(割边)在下一篇。伟大的RobertTarjan创造了众多被人们所熟知的算法及数据结构,最著名的如:(本文的)连通性相关的tarjan算法,Splay-Tree,Toptree,tarjan求lca等等。注:有向图的强连通分量、无向......
  • tarjan—算法的神(一)
    本篇包含tarjan求强连通分量、边双连通分量、割点部分,tarjan求点双连通分量、桥(割边)在下一篇。伟大的RobertTarjan创造了众多被人们所熟知的算法及数据结构,最著名的如:(本文的)连通性相关的tarjan算法,Splay-Tree,Toptree,tarjan求lca等等。注:有向图的强连通分量、无向......
  • 强连通分量(tarjan)
    前言首先你要知道什么是强连通分量再来,不会的话我给你链接啊!好像上面那个链接已经替代了我:)tarjantarjan这个算法的演示图比较复杂,我推荐看这篇博客,这时你肯定要问了,你都推荐别人的博客了,那我看你干嘛,别急,他没给你代可以给你!我们用\(dfn[x]\)表示点\(x\)dfs序(dfs遍历......
  • tarjan求LCA
    题面如题,给定一棵有根多叉树,请求出指定两个点直接最近的公共祖先。思路这次我们要使用的知识点是\(dfs\)和并查集,这个\(tarjan\)是离线的,我们要先把每个点的每一个要跟它求\(LCA\)的点给记录下来,接下来用\(dfs\)跑这么个流程:遍历这个点的每个子结点并进入子节点将子......
  • Tarjan 之 割点 学习笔记
    首先,要求割点,我们需要知道割点是什么割点:是指在无向连通图中,如果删除某个顶点后,图的连通分量增加,则称该顶点为割点好,知道了这个,那我们怎么去求他呢?Tarjan大神给出了一种依然基于时间戳的算法图片来源:董晓算法割点的求法大概就是这样的所以细节还是见代码吧#include<bit......
  • Tarjan 之 SCC 与 缩点
    这篇文章将讲述作者对Tarjan求SCC与缩点(不是割点)的理解让我们开始吧!TarjanSCC与缩点既然要求\(SCC\)那我们先要弄明白什么是SCCSCC指的是强连通分量强连通指的是若一张有向图的节点两两互相可达,则这张图是强连通的而强连通分量指的是一个极大的连通子图此处的极......
  • tarjan之LCA学习笔记
    tarjan之LCA学习笔记tarjan算法求LCA可谓是一个极其巧妙的离线算法其本质是利用DFS遍历时产生的DFS序和并查集来在线性的时间复杂度内求出所有询问的结果既然是离线算法,其和在线算法的区别就在与离线算法需要记录下所有查询,对查询进行一定操作来得到更高的效率,而这......
  • 【Tarjan缩点】USACO5.3 校园网Network of Schools】
    [P2746USACO5.3]校园网NetworkofSchools大意:一个图可能有环a:求deg入度为0的点的个数b:至少加多少条边让图所有点可以互相到达思路:看代码#include<cstdio>#include<queue>#include<deque>#include<stack>#include<map>#include<cmath>#include<algorit......