ccf csp-201509-4-高速公路(Tarjan算法求强连通分量)

Faustine ·
更新时间:2024-09-21
· 928 次阅读

原试题点击此处

强连通分量概念: 强连通分量中的结点能够相互到达。 Tarjan算法思想:

两条腿走路

一条腿深搜下去 一条腿回看(能不能回到自己本身)
在这里插入图片描述
如果从一个结点出发能回到这个结点本身,就构成了一个回路(轮回),回路中的点因为处于轮回中自然能够相互到达,即该回路也就构成了一个强连通分量Tarjan算法采用的数据结构: dfn:记录时间戳,即访问结点的先后时间顺序(深搜
low:记录能够返回的最浅的时间戳(回看每次深搜/回看完了以后,都要更新一下low值。 stack栈来记录强连通分量中具体的点: 1、每访问一次结点,就让结点入栈。 2、遇到dfn=low的点(即能从自己出发回到自己的点,可以看做强连通分量的根), 开始不断从栈顶弹出元素,直到dfn=low的点也出了栈(即让强连通分量出栈)。

Tarjan算法详解点击此处

代码如下

#include #include #include #include using namespace std; const int N = 10005; int n,m,top=0,index=0,ans=0,dfn[N]={0},low[N]={0},stk[N]={0},inStk[N]={0}; vector v[N]; void tarjan(int root){ if(dfn[root]) return; dfn[root]=low[root]=++index; stk[++top]=root; inStk[root] = 1; for(int i = 0; i < v[root].size(); i++){ int k = v[root][i]; if(!dfn[k]){ tarjan(k);//dfs过程 low[root]=min(low[root],low[k]);//回溯的时候更新一下low值 }else if(inStk[k]){//能指向时间戳更小的点 low[root]=min(low[root],low[k]); } } if(low[root]==dfn[root]){ int sum = 0; while(1){ int x = stk[top--]; inStk[x] = 0; sum++; if(x==root) break; } ans += (sum*(sum-1))/2; } } int main() { int a,b; scanf("%d%d", &n, &m); for(int i = 0; i < m; i++){ scanf("%d%d", &a, &b); v[a].push_back(b); } for(int i = 1; i <= n; i++){ if(!dfn[i]) tarjan(i); } printf("%d\n", ans); return 0; }
作者:波点兔



强连通分量 高速公路 连通分量 tarjan csp

需要 登录 后方可回复, 如果你还没有账号请 注册新账号