ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

tarjan大合辑

2022-06-03 12:00:07  阅读:100  来源: 互联网

标签:tarjan 大合辑 int ++ read while dfn low


\(tarjan\) 大合辑

1.割边:

#include<bits/stdc++.h>
using namespace std;
const int N = 1e5 + 10, M = 1e6 + 10;
int hd[N], nt[M], to[M], tot = 1;/////// tot = 1反边
inline void add(int u, int v)
{
	nt[++tot] = hd[u];
	hd[u] = tot;
	to[tot] = v;
}
int n, m;
int x; char v;
inline int read()
{
	x = 0;
	while(!isdigit(v)) v = getchar();
	while(isdigit(v)) x = (x << 1) + (x << 3) + v - 48, v = getchar();
	return x;
}
int dfn[N], low[N], now;
bool mark[N];//////////// 割边
inline void tarjan(int u, int fa)
{
	dfn[u] = low[u] = ++now;
	int v;
	for(int e = hd[u]; e; e = nt[e])
		if((v = to[e]) ^ fa)/////////// 无向图判回
		{
			if(!dfn[v])
			{
				tarjan(v, u);
				low[u] = min(low[u], low[v]);
			}
			else low[u] = min(low[u], dfn[v]);
			if(low[v] > dfn[u])///////////////// >
			    mark[e] = mark[e ^ 1] = true;/// 正反标记
		}
}
int main()
{ 
    n = read(), m = read();
    for(int i = 1, u, v; i <= m; ++i)
        u = read(), v = read(), add(u, v), add(v, u);
    for(int i = 1; i <= n; ++i)
        if(!dfn[i])
            tarjan(i, 0);
	return 0;
}

2.割点:

#include<bits/stdc++.h>
using namespace std;
const int N = 1e5 + 10, M = 1e6 + 10;
int hd[N], nt[M], to[M], tot = 1;
inline void add(int u, int v)
{
	nt[++tot] = hd[u];
	hd[u] = tot;
	to[tot] = v;
}
int n, m;
int x; char v;
inline int read()
{
	x = 0;
	while(!isdigit(v)) v = getchar();
	while(isdigit(v)) x = (x << 1) + (x << 3) + v - 48, v = getchar();
	return x;
}
int dfn[N], low[N], now;
bool mark[N];/////////////// 割点
int rt, res;
inline void tarjan(int u, int fa)
{
	dfn[u] = low[u] = ++now;
	int v, cnt = 0;
	for(int e = hd[u]; e; e = nt[e])
		if((v = to[e]) ^ fa)
		{
			if(!dfn[v])
			{
				tarjan(v, u);
				low[u] = min(low[u], low[v]);
				if(low[v] >= dfn[u])/////////// >=
				{
					++cnt;////////////////////
					if(cnt > 1 || (rt ^ u))/// 根特殊处理
		        		mark[u] = true;///////
				} 	
			}
			else low[u] = min(low[u], dfn[v]);
		}
}
int main()
{ 
    n = read(), m = read();
    for(int i = 1, u, v; i <= m; ++i)
        u = read(), v = read(), add(u, v), add(v, u);
    for(int i = 1; i <= n; ++i)
        if(!dfn[i])
            rt = i, tarjan(i, 0);///////// 赋rt
    for(int i = 1; i <= n; ++i)
        if(mark[i])
        	cout << i << ' ';
	return 0;
}

3.边双 \(DCC\)

#include<bits/stdc++.h>
using namespace std;
const int N = 1e5 + 10, M = 1e6 + 10;
int x; char v;
inline int read()
{
	x = 0;
	while(!isdigit(v)) v = getchar();
	while(isdigit(v)) x = (x << 1) + (x << 3) + v - 48, v = getchar();
	return x;
}
int n, m;
int hd[N], nt[M], to[M], tot = 1;
inline void add(int u, int v)
{
	nt[++tot] = hd[u];
	hd[u] = tot;
	to[tot] = v;
}
int dfn[N], low[N], now;
vector <int> g[N];
int cl[N], co;
bool mark[N];
inline void tarjan(int u, int fa)/////////// 和割边一模一样
{
	dfn[u] = low[u] = ++now;
	int v;
	for(int e = hd[u]; e; e = nt[e])
	    if((v = to[e]) ^ fa)
	    {
	    	if(!dfn[v])
	    	{
	    		tarjan(v, u);
	    		low[u] = min(low[u], low[v]);
	    		if(low[v] > dfn[u])
	    	        mark[e] = mark[e ^ 1] = true, cout << u << ' ' << v << '\n';
			}
			else low[u] = min(low[u], dfn[v]);
		}
}
inline void getDCC(int u)////////////////
{
	cl[u] = co;//////////////////////////
	int v;///////////////////////////////
	for(int e = hd[u]; e; e = nt[e])/////
	    if(!mark[e] && !cl[v = to[e]])/// 找DCC,把桥断了即可
	    	getDCC(v);//////////////////
}
int main()
{ 
    n = read(), m = read();
    for(int i = 1, u, v; i <= m; ++i)
        u = read(), v = read(), add(u, v), add(v, u);
    for(int i = 1; i <= n; ++i)
        if(!dfn[i])
            tarjan(i, 0);
    for(int i = 1; i <= n; ++i)
        if(!cl[i])
            ++co, getDCC(i);
    for(int i = 1; i <= n; ++i) g[cl[i]].push_back(i);//////// 连通分量的搞
    for(int i = 1, k; i <= co; ++i)//////////
    {////////////////////////////////////////
    	cout << i << ':';////////////////////
    	cout << (k = g[i].size()) << "  ";/// 连通分量输出板子
		for(int j = 0; j < k; ++j)///////////
		    cout << g[i][j] << ' ';//////////
		cout << '\n';////////////////////////
	}
	return 0;
}
/*
12 15
1 2 
2 3 
3 4 
4 1 
4 5 
5 6 
5 12
5 7 
5 8 
6 8 
8 7
7 9
9 10 
10 11 
11 9*/

4.点双 \(BCC\)

#include<bits/stdc++.h>
using namespace std;
const int N = 1e5 + 10, M = 1e6 + 10;
int x; char v;
inline int read()
{
	x = 0;
	while(!isdigit(v)) v = getchar();
	while(isdigit(v)) x = (x << 1) + (x << 3) + v - 48, v = getchar();
	return x;
}
int n, m;
int hd[N], nt[M], to[M], tot = 1;
inline void add(int u, int v)
{
	nt[++tot] = hd[u];
	hd[u] = tot;
	to[tot] = v;
}
int dfn[N], low[N], now;
bool mark[N];
vector <int> in[N];
vector <int> g[N];
int stk[N], top, cl[N], co;
inline void tarjan(int u, int fa)
{
	stk[++top] = u;
	dfn[u] = low[u] = ++now;
	int v;
	for(int e = hd[u]; e; e = nt[e])
	    if((v = to[e]) ^ fa)
	    {
	    	if(!dfn[v])
	    	{
	    		tarjan(v, u);
	    		low[u] = min(low[u], low[v]);
	    		if(low[v] >= dfn[u])
	    		{
	    			mark[u] = true;///////////////////////////////////
	    			++co;///////////////////////////////////////////// 不能只搞u,不然丢失尾部割点
	    			do{/////////////////////////////////////////////// 不能在外面搞割点,不然重复
	    			    if(mark[v = stk[top]]) in[v].push_back(co);/// 割点和普通点分开搞
	    			    else cl[v] = co;//////////////////////////////
					} while(stk[top--] ^ u);///////////////////////// 弹栈 不弹割点 
	    			++top;/////////////////////////////////////////// 唯一一个不弹u的
				}
			}
			else low[u] = min(low[u], dfn[v]);
		}
}
int main()
{ 
    n = read(), m = read();
    for(int i = 1, u, v; i <= m; ++i)
        u = read(), v = read(), add(u, v), add(v, u);
    for(int i = 1; i <= n; ++i)
        if(!dfn[i])
            tarjan(i, 0);
    for(int i = 1, k; i <= n; ++i)////////////
    	if(!mark[i]) g[cl[i]].push_back(i);///
    	else//////////////////////////////////
    	{///////////////////////////////////// 分割点和普通点分开高
    		k = in[i].size();/////////////////
    		for(int j = 0; j < k; ++j)////////
    		    g[in[i][j]].push_back(i);/////
		}/////////////////////////////////////
    for(int i = 1, k; i <= co; ++i)
    {
    	cout << i << ':';
    	cout << (k = g[i].size()) << "  ";
		for(int j = 0; j < k; ++j)
		    cout << g[i][j] << ' '; 
		cout << '\n';
	}
	return 0;
}
/*
12 15
1 2 
2 3 
3 4 
4 1 
4 5 
5 6 
5 12
5 7 
5 8 
6 8 
8 7
7 9
9 10 
10 11 
11 9*/

5.强连通分量

#include<bits/stdc++.h>
using namespace std;
const int N = 1e5 + 10, M = 1e6 + 10;
int x; char v;
inline int read()
{
	x = 0;
	while(!isdigit(v)) v = getchar();
	while(isdigit(v)) x = (x << 1) + (x << 3) + v - 48, v = getchar();
	return x;
}
int n, m;
int hd[N], nt[M], to[M], tot = 1;
inline void add(int u, int v)
{
	nt[++tot] = hd[u];
	hd[u] = tot;
	to[tot] = v;
}
int dfn[N], low[N], now;
int stk[N], top, cl[N], co;
bool in[N];
vector <int> g[N];
inline void tarjan(int u)
{
	dfn[u] = low[u] = ++now;
	stk[++top] = u;
	in[u] = true;
	int v;
	for(int e = hd[u]; e; e = nt[e])
	{
		if(!dfn[v = to[e]]) 
		{
			tarjan(v);
			low[u] = min(low[u], low[v]);
		}
		else if(in[v]) low[u] = min(low[u], dfn[v]); 
        //////////// 要判断在栈中,因为有向图要保证能走回去
	}
	if(dfn[u] == low[u])/////////////////////////////
	{
		++co;//////////////////////////////////////// 最后弹
		do {cl[v = stk[top]] = co; in[v] = false;}///
	    while(stk[top--] ^ u);///////////////////////
	}
}
int main()
{ 
    n = read(), m = read();
    for(int i = 1, u, v; i <= m; ++i)
        u = read(), v = read(), add(u, v);
    for(int i = 1; i <= n; ++i)
        if(!dfn[i])
            tarjan(i);
    for(int i = 1; i <= n; ++i) 
        g[cl[i]].push_back(i); 
    for(int i = 1, k; i <= co; ++i)
    {
    	cout << i << ':';
    	cout << (k = g[i].size()) << "  ";
		for(int j = 0; j < k; ++j)
		    cout << g[i][j] << ' '; 
		cout << '\n';
	}
	return 0;
}
/*
5 8
1 3
1 2
3 5
3 4
3 2
4 5
4 1
5 1*/

标签:tarjan,大合辑,int,++,read,while,dfn,low
来源: https://www.cnblogs.com/fakeryu/p/16339779.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有