tarjan vDCC缩点 模板
作者:互联网
代码
//fw
#include<iostream>
#include<cstdio>
#include<fstream>
#include<algorithm>
#include<cmath>
#include<deque>
#include<vector>
#include<queue>
#include<string>
#include<cstring>
#include<map>
#include<stack>
#include<set>
#include<climits>
#define zp ios::sync_with_stdio(false);cin.tie(0); cout.tie(0);
#define pii pair <int, int>
#define endl '\n'
#define pb push_back
#define lc u<<1
#define rc u<<1|1
using namespace std;
typedef long long ll;
const int INF=0x3f3f3f3f;
const int N=1e5+10,M=1e6+10;
int n,m,h[N],hs[N],e[N],ne[N],idx;
int dfn[N],low[N],times,stk[N],top,dcc_cnt,root;
vector<int>dcc[N];
bool cut[N];
int id[N];
void add(int h[],int a,int b)
{
e[idx]=b;
ne[idx]=h[a];
h[a]=idx++;
}
void tarjan(int u)
{
dfn[u]=low[u]=++times;//初始化时间戳和能访问到的最早时间戳点
stk[++top]=u;//入栈
if(u==root&&h[u]==-1)//如果是一个孤立的点
{
//记录该vdcc
dcc_cnt++;
dcc[dcc_cnt].push_back(u);
return;
}
int cnt=0;//满足条件的数量
for(int i=h[u];~i;i=ne[i])//遍历邻点
{
int j=e[i];
if(!dfn[j])//没访问过
{
//访问并更新low
tarjan(j);
low[u]=min(low[u],low[j]);
if(dfn[u]<=low[j])//如果符合该条件
{
cnt++;//计数
if(u!=root||cnt>1)//如果不是根节点则cnt至少需要2才能判割点,是根节点cnt有1即可
cut[u]=true;
dcc_cnt++;//计数
int y;
do
{
//记录vdcc
y=stk[top--];
dcc[dcc_cnt].push_back(y);
}while(y!=j);//不是u !!!
dcc[dcc_cnt].push_back(u);//把最后一个点加入vdcc
}
}
else
low[u]=min(low[u],dfn[j]);//更新
}
}
int main()
{
memset(h,-1,sizeof h);
memset(hs,-1,sizeof hs);
cin>>n>>m;
//建原图
while(m--)
{
int a,b;
cin>>a>>b;
add(h,a,b);
add(h,b,a);
}
//求vdcc
for(root=1;root<=n;root++)
if(!dfn[root])
tarjan(root);
//给割点编号
int num=dcc_cnt;
for(int i=1;i<=n;i++)
if(cut[i])
id[i]=++num;
//建新图
for(int i=1;i<=dcc_cnt;i++)//遍历所有vdcc
{
//遍历vdcc中的每个点
for(int j=0;j<dcc[i].size();j++)
{
//取出这个点
int x=dcc[i][j];
if(cut[x])//如果是割点
{
//用vdcc中的割点代表缩点后的连通分量并建边
add(hs,i,id[x]);
add(hs,id[x],i);
}
}
}
return 0;
}
标签:缩点,tarjan,int,cnt,dcc,vDCC,low,include,define 来源: https://www.cnblogs.com/avarice/p/16504117.html