首页 > 其他分享 >tarjan 全家桶

tarjan 全家桶

时间:2024-01-28 16:56:10浏览次数:21  
标签:tarjan last int 全家 alen dfn low

无向图的tarjan

求边双连通分量的个数以及每个边双连通分量的大小以及每个边双连通分量包含哪些点。bridge数组表示一条边是不是桥。

#include<bits/stdc++.h>
using namespace std;
const int N=5e5+10,M=2e6+10;
struct edge{
	int x,y,pre;
}a[M*2];
int alen,last[N];
void ins(int x,int y)
{
	a[++alen]={x,y,last[x]};
	last[x]=alen;
}
int dfn[N],low[N],id;
bool bridge[M*2];
void tarjan(int x,int in_edge)
{
	low[x]=dfn[x]=++id;
	for(int k=last[x];k;k=a[k].pre)
	{
		int y=a[k].y;
		if(!dfn[y])
		{
			tarjan(y,k);
			low[x]=min(low[x],low[y]);
			if(low[y]>dfn[x]) bridge[k]=bridge[k^1]=1;
		}
		else if(k!=(in_edge^1)) low[x]=min(low[x],dfn[y]);
	}
}
int cnt;
bool v[N];
vector<int> dcc[N];
void dfs(int x)
{
	v[x]=1;
	dcc[cnt].push_back(x);
	for(int k=last[x];k;k=a[k].pre)
	{
		int y=a[k].y;
		if(v[y]||bridge[k]) continue;
		dfs(y);
	}
}
int main()
{
	int n,m;
	scanf("%d%d",&n,&m);
	alen=1;memset(last,0,sizeof(last));
	for(int i=1;i<=m;i++)
	{
		int x,y;
		scanf("%d%d",&x,&y);
		if(x==y) continue;
		ins(x,y),ins(y,x);
	}
	id=0;
	for(int i=1;i<=n;i++) if(!dfn[i]) tarjan(i,-1);
	for(int i=1;i<=n;i++) if(!v[i]) cnt++,dfs(i);
	printf("%d\n",cnt);//边双连通分量的数目
	for(int i=1;i<=cnt;i++)
	{
		printf("%d ",(int)dcc[i].size());//当前边双连通分量的大小
		for(auto x:dcc[i]) printf("%d ",x);//当前边双连通分量包含哪些点
	}
	return 0;
}

点双tarjan一定要判断自环!

求一个点是不是割点。cut数组表示一个点是不是割点。

#include<bits/stdc++.h>
using namespace std;
const int N=2e4+10,M=1e5+10;
struct edge{
	int x,y,pre;
}a[M*2];
int alen,last[N];
void ins(int x,int y)
{
	a[++alen]={x,y,last[x]};
	last[x]=alen;
}
int dfn[N],low[N],id,root;
bool cut[N];
void tarjan(int x)
{
	low[x]=dfn[x]=++id;
	int flag=0;
	for(int k=last[x];k;k=a[k].pre)
	{
		int y=a[k].y;
		if(!dfn[y])
		{
			tarjan(y);
			low[x]=min(low[x],low[y]);
			if(low[y]>=dfn[x])
			{
				flag++;
				if(x!=root||flag>1) cut[x]=true;
			}
		}
		else low[x]=min(low[x],dfn[y]);
	}
}
int main()
{
	int n,m;
	scanf("%d%d",&n,&m);
	for(int i=1;i<=m;i++)
	{
		int x,y;
		scanf("%d%d",&x,&y);
		ins(x,y),ins(y,x);
	}
	for(int i=1;i<=n;i++) if(!dfn[i]) root=i,tarjan(i);
	int cnt=0;
	for(int i=1;i<=n;i++) if(cut[i]) cnt++;
	printf("%d\n",cnt);//割点的数量
	for(int i=1;i<=n;i++) if(cut[i]) printf("%d ",i);//每个割点的编号
	return 0;
}

求点双连通分量的个数以及每个点双连通分量的大小以及每个点双连通分量包含哪些点

#include<bits/stdc++.h>
using namespace std;
const int N=5e5+10,M=2e6+10;
struct edge{
	int x,y,pre;
}a[M*2];
int alen,last[N];
void ins(int x,int y)
{
	a[++alen]={x,y,last[x]};
	last[x]=alen;
}
int dfn[N],low[N],id,root;
vector<int> dcc[N];
int cnt;
stack<int> sta;
void tarjan(int x)
{
	low[x]=dfn[x]=++id;
	if(x==root&&!last[x]) return dcc[++cnt].push_back(x);
    sta.push(x);
	for(int k=last[x];k;k=a[k].pre)
	{
		int y=a[k].y;
		if(!dfn[y])
		{
			tarjan(y);
			low[x]=min(low[x],low[y]);
			if(low[y]>=dfn[x])
			{
				cnt++;
				int z;
				do
				{
					z=sta.top();
					sta.pop();
					dcc[cnt].push_back(z);
				} while(z!=y);
				dcc[cnt].push_back(x);
			}
		}
		else low[x]=min(low[x],dfn[y]);
	}
}
int main()
{
	int n,m;
	scanf("%d%d",&n,&m);
	for(int i=1;i<=m;i++)
	{
		int x,y;
		scanf("%d%d",&x,&y);
		if(x==y) continue;
		ins(x,y),ins(y,x);
	}
	for(int i=1;i<=n;i++) if(!dfn[i]) root=i,tarjan(i);
	printf("%d\n",cnt);//点双连通分量的数量
	for(int i=1;i<=cnt;i++)
	{
		printf("%d ",(int)dcc[i].size());//当前点双连通分量的大小
		for(auto j:dcc[i]) printf("%d ",j);//当前点双连通分量包含哪些点
		puts("");
	}
	return 0;
}

有向图的tarjan

求出强连通分量的数量以及每个强连通分量的大小以及每个强连通分量包含哪些点

#include<bits/stdc++.h>
using namespace std;
const int N=1e4+10,M=1e5+10;
struct edge{
	int x,y,pre;
}a[M];
int alen,last[N];
void ins(int x,int y)
{
	a[++alen]={x,y,last[x]};
	last[x]=alen;
}
int dfn[N],low[N],id;
vector<int> scc[N];
int cnt;
stack<int> sta;
bool v[N];
void tarjan(int x)
{
	low[x]=dfn[x]=++id;
	sta.push(x),v[x]=1;
	for(int k=last[x];k;k=a[k].pre)
	{
		int y=a[k].y;
		if(!dfn[y])
		{
			tarjan(y);
			low[x]=min(low[x],low[y]);
		}
		else if(v[y]) low[x]=min(low[x],low[y]);
	}
	if(low[x]==dfn[x])
	{
		cnt++;
		int y;
		do
		{
			y=sta.top();
			sta.pop(),v[y]=0;
			scc[cnt].push_back(y);
		}while(y!=x);
	}
}
int main()
{
	int n,m;
	scanf("%d%d",&n,&m);
	for(int i=1;i<=m;i++)
	{
		int x,y;
		scanf("%d%d",&x,&y);
		ins(x,y);
	}
	for(int i=1;i<=n;i++) if(!dfn[i]) tarjan(i);
	printf("%d\n",cnt);//强连通分量的数量
	for(int i=1;i<=cnt;i++)
	{
		printf("%d\n",scc[i].size());//当前强连通分量的大小
		for(auto j:scc[i]) printf("%d ",j);//当前强连通分量包含哪些点
		puts("");
	}
	return 0;
}

标签:tarjan,last,int,全家,alen,dfn,low
From: https://www.cnblogs.com/StarSky2008/p/17993008

相关文章

  • Tarjan
    Tarjan前置知识搜索树&搜索森林\(在一张连通图中,所有的节点以及发生递归的边共同构成一棵搜索树。如果这张图不连通,则构成搜索森林。\)\(\color{green}树边:\)\(dfs经过的边,dfs搜索树の边\)\(\color{yellow}返祖边:\)\(可以理解为返回去の边\)\(\color{red}横叉边:\)\(df......
  • Tarjan 算法(超详细!!)
    Tarjan算法前言说来惭愧,这个模板仅是绿的算法至今我才学会。我还记得去年CSP2023坐大巴路上拿着书背Tarjan的模板。虽然那年没有考连通分量类似的题目。现在做题遇到了Tarjan,那么,重学,开写!另,要想学好此算法的第一件事——膜拜Tarjan爷爷。Tarjan算法到底是什么其......
  • 我的多项式全家桶
    第一个自己实现的多项式全家桶。打比赛时终于有板子了!代码是从之前学转置原理的那篇博客里升级来的。但是功能很残?效率很逊?接口很怪?评价是能用就行。目前封装了:乘、逆、除(取模)、开方(无二次剩余,不会qwq)、对数、指数、多点求值、快速插值、常系数齐次线性递推、Berlekamp-Massey......
  • 手机全家桶买哪个品牌好?
    手机全家桶买哪个品牌好?选择手机全家桶品牌时,通常要考虑多个因素,包括品牌的声誉、产品质量、性能、价格、生态系统和客户支持等。以下是几个备受认可的手机全家桶品牌:1.Apple(苹果):苹果提供一系列无缝集成的产品,包括iPhone手机、iPad平板电脑、Mac电脑和AppleWatch智能手表。它......
  • DevOps常用工具全家桶,实现高效运维和交付
     DevOps常用工具全家桶,实现高效运维和交付1、DevOps发展DevOps发展背景:随着互联网技术的快速发展,软件开发和运维的挑战也日益增加。传统的软件开发和运维模式往往存在分离、效率低下、沟通不畅等问题,导致软件交付速度缓慢,质量参差不齐。为了解决这些问题,DevOps应运而生。De......
  • Tarjan的学习笔记
    \(Tarjan\)的学习笔记一,\(tarjan\)概述:(1)定义:$~~~~~~~~$$tarjan$是基于深度优先搜索的一种算法,求解图的连通性等问题,巧妙地利用了对图进行深搜时产生的搜索树上的边。(2)\(tarjan\)中的几种边:\(~~~~~~~~\)树边:父亲与孩子的边。\(~~~~~~~~\)前向边:祖先到孩子的边(树边属于特......
  • hszxoj 矿场搭建 [tarjan]
    hszxoj矿场搭建题目描述原题来自:HNOI2012煤矿工地可以看成是由隧道连接挖煤点组成的无向图。为安全起见,希望在工地发生事故时所有挖煤点的工人都能有一条出路逃到救援出口处。于是矿主决定在某些挖煤点设立救援出口,使得无论哪一个挖煤点坍塌之后,其他挖煤点的工人都有一条道......
  • 学习Vue3 第六章(认识Ref全家桶)
    ref接受一个内部值并返回一个响应式且可变的ref对象。ref对象仅有一个 .value property,指向该内部值<template><div><button@click="changeMsg">change</button><div>{{message}}</div></div></template><......
  • tarjan无向图割点板子
    //无向图割点模板#include<bits/stdc++.h>#defineintlonglong#defineendl'\n'#defineN20001usingnamespacestd;template<typenameTp>inlinevoidread(Tp&x){x=0;registerboolf=1;registercharc=getchar();for(;c&......
  • 树分治全家桶
    树分治全家桶树,(是种在路边的绿化植物)是图论当中的一种特殊图,(由于绿化环境作用非常优秀)由于特殊性质丰富,经常出现在我们身边。本文将主要讲述(如何植树)一种树上优美的暴力——树分治。树分治树分治可以将部分\(O(n^2)\)的暴力降至\(O(n\logn)\)级别,尤其适用于树上距离及其......