Tarjan

强连通

定义:

有向图强连通分量:在有向图G中,如果两个顶点vi,vj间(vi>vj)有一条从vi到vj的有向路径,同时还有一条从vj到vi的有向路径,则称两个顶点强连通(strongly connected)。

如果有向图G的每两个顶点都强连通,称G是一个强连通图。

有向图的极大强连通子图,称为强连通分量(strongly connected components)。

 1 void tarjan(int cur){
 2     dfn[cur] = low[cur] = ++t_cnt;
 3     stack[++s_size] = cur; instack[cur] = 1;
 4     for(int i = head[cur]; i != -1; i = edge[i].next){
 5         int v = edge[i].v;
 6         if(!dfn[v]){
 7             tarjan(v);
 8             low[cur] = min(low[cur], low[v]);
 9         }
10         else if(instack[v])//栈里的是来时路上的点 当然可以到达当前点 所以可以更新
11             low[cur] = min(low[cur], low[v]);
12     }
13     if(dfn[cur] == low[cur]){
14         col_size++;
15         do{
16             int temp = stack[s_size];
17             color[temp] = col_size;
18             instack[temp] = 0;
19         }while(stack[s_size--] != cur);
20     }
21 }
强连通(包括染色

双联通

双连通分量又分 点双连通分量 和 边双连通分量 两种。

若一个无向图中的去掉任意一个节点(一条边)都不会改变此图的连通性,即不存在割点(桥),则称作点(边)双连通图。

说白了就是找环啦

一个无向图中的每一个极大点(边)双连通子图称作此无向图的点(边)双连通分量。

这里就不附带代码了 因为和找割点极为类似

缩点

其实就是把一个强连通分量缩成一个点

 1 void tarjan(int cur){
 2     dfn[cur] = low[cur] = ++t_cnt;
 3     stack[++s_size] = cur; instack[cur] = 1;
 4     for(int i = head[cur]; i != -1; i = edge[i].next){
 5         int v = edge[i].v;
 6         if(!dfn[v]){
 7             tarjan(v);
 8             low[cur] = min(low[cur], low[v]);
 9         }
10         else if(instack[v])
11             low[cur] = min(low[cur], low[v]);
12     }
13     if(dfn[cur] == low[cur]){
14         col_size++;
15         do{
16             int temp = stack[s_size];
17             color[temp] = col_size;
18             nw[col_size] += w[temp];//只多这一句话
19             instack[temp] = 0;
20         }while(stack[s_size--] != cur);
21     }
22 }
缩点

割点

 1 void tarjan(int x, int fa){
 2     int ch = 0;
 3     dfn[x] = low[x] = ++t_cnt;
 4     for(int i = head[x]; i != -1; i = edge[i].next){
 5         int vv = edge[i].v;
 6         if(vv == fa)continue;
 7         if(!dfn[vv]){
 8             ch++;
 9             tarjan(vv, x);
10             low[x] = min(low[x], low[vv]);
11             if(low[vv] >= dfn[x]) cut[x] = 1;
12         }
13         low[x] = min(low[x], dfn[vv]);//关键是这里!与强连通不同
14     }
15     if(fa == -1 && ch <= 1) cut[x] = 0;
16 }
割点

lca

 1 void tarjan(int x){
 2     vis[x] = 1;
 3     for(int i = head[x]; i != -1; i = edge[i].next){
 4         int vv = edge[i].v;
 5         if(vis[vv]) continue;
 6         tarjan(vv);
 7         fa[vv] = x;
 8     }
 9     for(int i = hq[x]; i != -1; i = q[i].next){
10         int vv = q[i].v;
11         if(vis[vv]) ans[q[i].id] = find(vv);
12     }
13 }
LCA

相关题目:

原文地址:https://www.cnblogs.com/hjmmm/p/9190101.html