题目很简单就拿着这道题简单说说 有向图强连通分支的Tarjan算法
有向图强连通分支的Tarjan算法伪代码如下:
void Tarjan(u) {
dfn[u]=low[u]=++index//进行DFS,每发现一个新的点就对这个点打上时间戳,所以先找到的点时间戳越早,dfn[U]表示最早发现u的时间,low[u]表示u能到达的最早的时间戳。
stack.push(u)//将U压入栈中
for each (u, v) in E {
if (v is not visted)//如果V点没有经历过DFS,则对V点进行搜索
{
tarjan(v)
low[u] = min(low[u], low[v]) //因为U和V连接,所以V能到达的最早的时间戳,U一定可以到达,比较后取小值。
}
else if (v in stack)//如果V点已经在栈中了,那么比较dfn[V]和low[u]后取小值
{
low[u] = min(low[u], dfn[v])
}
}
if (dfn[u] == low[u]) { //u是一个强连通分量的根
repeat
v = stack.pop
print v
until (u== v)
} //退栈,把整个强连通分量都弹出来
} //复杂度是O(E+V)的
下面贴出HDU1269的代码,这是道很基础的模板题。
#include<cstdio> #include<cstdlib> #include<cmath> #include<iostream> #include<algorithm> #include<cstring> #include<vector> #include<queue> #define INF 0xfffffff #define MAX 101000 using namespace std; int n,m,k,Time,vis[MAX],low[MAX],dfn[MAX],black,e,Stack[MAX]; vector<vector<int> >G; void Tarjan(int u) { vis[u]=1; Stack[++k]=u; low[u]=dfn[u]=Time++; int v,len=G[u].size(),i; for(i=0;i<len;i++) { v=G[u][i]; if(!dfn[v]) { Tarjan(v); low[u]=min(low[u],low[v]); } else if(vis[v]) { low[u]=min(low[u],dfn[v]); } } if(dfn[u]==low[u]) { do { v=Stack[k--]; e++; vis[v]=0; }while(u!=v); black++; } } int main() { int i,j,a,b; while(scanf("%d%d",&n,&m),n+m) { Time=1; k=e=black=0; memset(vis,0,sizeof(vis)); memset(low,0,sizeof(low)); memset(dfn,0,sizeof(dfn)); memset(Stack,0,sizeof(Stack)); G.clear(); G.resize(n+1); for(i=1;i<=m;i++) { scanf("%d%d",&a,&b); G[a].push_back(b); } Tarjan(1); if(e==n && black==1) printf("Yes "); else printf("No "); } return 0; }