HDU-1269 Tarjan求强连通分量,模板题

HDU 1269

题意:n个点m条单向边,问任意两个点是否连通。

总结:参考大神博客码的,有些地方还是不太明白。 而且这题还可以双向dfs做,有时间再做一下。

// HDU-1269 
#include<bits/stdc++.h>
using namespace std;
#pragma comment(linker, "/STACK:102400000,102400000")
#define F(i,a,b)  for (int i=a;i<b;i++)
#define FF(i,a,b) for (int i=a;i<=b;i++)
#define mes(a,b)  memset(a,b,sizeof(a))
#define INF 0x3f3f3f3f
typedef long long ll;
const int N = 1e4+10, M = 1e5+10;

int n, m, sum, top, tot;    //sum为强连通分量数,top为栈指针
int head[N], Stack[N], instack[N];  //Stack[]为模拟栈,instack[]表示是否在栈中
int dfn[N], low[N], Belong[N];     
//dfn[]为深搜次序数组,Low[u]为u结点或者u的子树结点所能追溯到的最早栈中结点的次序号,这两个数组是关键。Belong[]表示每个结点所对应的强连通分量标号数组,这个题里用不到
struct Edge { int to, next; } edge[M];

void Init()
{
    sum=top=tot=0;
    mes(head, -1);
    mes(dfn, 0);
}
void Addedge(int u, int v)
{
    edge[tot].to=v;
    edge[tot].next=head[u];
    head[u]=tot++;
}
void Tarjan(int u)      //Tarjan算法求有向图的强连通分量   
{
    dfn[u]=low[u]=++tot;  //时间戳,不太明白
    Stack[top++]=u, instack[u]=1;
    for(int e=head[u]; e!=-1; e=edge[e].next) {
        int v=edge[e].to;
        if(dfn[v]==0) {
            Tarjan(v);
            if(low[u]>low[v]) low[u]=low[v];  //更新结点v所能到达的最小次数层,这里不太明白
        }
        else if(instack[v] && low[u]>dfn[v]) {
            low[u]=dfn[v];
        }
    }
    if(dfn[u]==low[u]) {  //如果节点v是强连通分量的根   
        sum++;
        while(top!=0) {
            int t=Stack[--top];
            instack[t]=0;
            Belong[t]=sum;
            if(t==u) break; //直到将v从栈中退出,这不太明白
        }
    }
}
void Solve()
{
    FF(i,1,n) if(dfn[i]==0)
        Tarjan(i);
}
int main()
{
    while(scanf("%d%d", &n, &m)!=EOF && (n||m)) {
        Init();
        FF(i,1,m) {
            int u, v;
            scanf("%d%d", &u, &v);
            Addedge(u, v);
        }
        Solve();
        if(sum==1) puts("Yes");
        else puts("No");
    }

    return 0;
}
Tarjan求强连通
posted @ 2017-01-25 16:54  v9fly  阅读(281)  评论(0编辑  收藏  举报