本文只给最直接的结论而没有证明,想看详细教程的可以退出了!
预备知识:
有向图:图中任意两个节点的连边是有方向的。
强连通:两个节点u,v。如果能在图中找出一条路劲从u到v,也能找出一条从v到u的路径,则称这两个节点是强连通的。
强连通图:图中任意两个节点之间都是强连通的。
极大强连通子图:往这个子图中加任意一个点都会使之不是强连通图,那么这个子图就是极大连通子图,也称强连通分量
改图的强连通分量有(1,2,3,4), (6), (5)。
tarjan算法旨在找出有向图的强连通分量。
我们确立两个数组
dfn[u]:利用深度优先搜索确定的u的dfs序
low[u]: u及u的子孙节点能够到的dfn最小的且未被删除的dfn序(未被删除可以暂时忽略),初始时我们将每个节点的low值设为dfn值(每个节点至少可以够到自己)
一些结论(不给证明)
一个强连通分量有且仅有一个唯一的根
如果节点u,有dfn[u] == low[u],则u是强连通分量的一个根
我们可以任意找一个节点进行dfs,将未访问的点推入一个栈s中,当这跳入没有了出度,正在回溯时,我们可以回溯点的dfn与low是否相等,如果相等,我们可以将该节点在栈中以上的点全部推出,则该节点与退出的所有节点构成一个强连通分量
void tarjan(int u)
{
dfn[u] = low[u] = ++d_time;
s.push(u), instack[u] = 1;//遇到一个点就放进栈中
for(int i = 0; i < (int) g[u].size(); ++i)
{
int v = g[u][i];
if(!dfn[v])//v还未被访问
{
tarjan(v);
low[u] = min(low[u], low[v]);//回溯时更新low值
}
else if(instack[v])//v未被访问但是仍然在栈中
{
low[u] = min(low[u], dfn[v]);
}
}
if(dfn[u] == low[u])
{
k++;
while(true)
{
int temp = s.top();
s.pop();
instack[temp] = 0;
if(temp == u) break;
}
}
}
题解:
#include<bits/stdc++.h>
using namespace std;
const int N = 1e4 + 2;
int n,m, dfn[N], low[N], instack[N], d_time;
int k;//强连通分量的个数
vector<int> g[N];
stack<int> s;
void tarjan(int u)
{
dfn[u] = low[u] = ++d_time;
s.push(u), instack[u] = 1;//遇到一个点就放进栈中
for(int i = 0; i < (int) g[u].size(); ++i)
{
int v = g[u][i];
if(!dfn[v])//v还未被访问
{
tarjan(v);
low[u] = min(low[u], low[v]);//回溯时更新low值
}
else if(instack[v])//v未被访问但是仍然在栈中
{
low[u] = min(low[u], dfn[v]);
}
}
if(dfn[u] == low[u])
{
k++;
while(true)
{
int temp = s.top();
s.pop();
instack[temp] = 0;
if(temp == u) break;
}
}
}
void init()
{
while(!s.empty()) s.pop();
d_time = k = 0;
for(int i = 1; i <= n; ++i)
{
g[i].clear();
}
memset(instack + 1, 0, n*sizeof(int));
memset(dfn+1, 0, n*sizeof(int));
memset(low + 1, 0, n * sizeof(int));
}
int main()
{
while(scanf("%d%d", &n, &m) && (n || m))
{
init();
for(int i = 0; i < m; ++i)
{
int u, v;
scanf("%d%d", &u, &v);
g[u].push_back(v);
}
for(int i = 1; i <= n; ++i)
{
if(!dfn[i])//该图可能是不连通的,我们需要尝试遍历每一个点
{
tarjan(i);
}
}
if(k == 1)
{
printf("Yes\n");
}
else
{
printf("No\n");
}
}
return 0;
}