迷宫城堡

连通图 Time Limit:1000MS     Memory Limit:32768KB     64bit IO Format:%I64d & %I64u

Submit Status

Description

为了训练小希的方向感,Gardon建立了一座大城堡,里面有N个房间(N<=10000)和M条通道(M<=100000),每个通道都是 单向的,就是说若称某通道连通了A房间和B房间,只说明可以通过这个通道由A房间到达B房间,但并不说明通过它可以由B房间到达A房间。Gardon需要 请你写个程序确认一下是否任意两个房间都是相互连通的,即:对于任意的i和j,至少存在一条路径可以从房间i到房间j,也存在一条路径可以从房间j到房间 i。
 

Input

输入包含多组数据,输入的第一行有两个数:N和M,接下来的M行每行有两个数a和b,表示了一条通道可以从A房间来到B房间。文件最后以两个0结束。
 

Output

对于输入的每组数据,如果任意两个房间都是相互连接的,输出"Yes",否则输出"No"。
 

Sample Input

3 3
1 2
2 3
3 1
 
3 3
1 2
2 3
3 2
 
0 0
 

Sample Output

Yes
No
只要任意两点直接或间接连接,就是说这个图是一个强连通图;
#include<iostream>
#include<vector>
#include<cstring>
#include<algorithm>
#include<cstdio>
#include<stack>
#include<cmath>

using namespace std;

#define N 10008

int n, m, cnt, num, top, Time; // Time用来计量时间,top用来控制stackk数组的下标
int dfn[N], low[N], stackk[N];  // dfn数组存到达下标的最小时间,low存下标可以走到的最小的点,stackk是自己建的栈,用来存深搜先后进入的点
bool instack[N];  // 判断是否进栈

vector<vector<int> > G;

void init()   // 初始化
{
    G.clear();
    G.resize(n+1);
    memset(dfn, 0, sizeof(dfn));
    memset(low, 0, sizeof(low));
    memset(stackk, 0, sizeof(stackk));
    memset(instack, false, sizeof(instack));
    cnt = num = top = Time = 0;
}

void Tarjan(int u)  // 从1点开始进栈,进栈一次Time更新
{
    low[u] = dfn[u] = ++Time;
    stackk[top++] = u;
    instack[u] = true;  // 已经进栈就标记true
    int len = G[u].size(), v;  

    for(int i = 0; i < len; i++)
    {
        v = G[u][i];  // 与进栈的点所连接的点

        if(!dfn[v])  // 如果这个点还没有被访问过,就把这个点遍历,low随之更新,是原先值和连接的这个值的low的最小值,因为low是指下标所能到的最小的点
        {
            Tarjan(v);
            low[u] = min(low[u], low[v]);
        }
        else if(instack[v])  // 如果已经进栈,就直接判断low的取值就行了,
            low[u] = min(low[u], dfn[v]);
    }
    if(low[u] == dfn[u])  // 如果两个点的第一次到的时间值dfn和可以到的最小值dfn一样,说明不能再往下走了,这个连通图结束,开始出栈
    {
        do
        {
            num++;   // 出栈一个数num++,计量出栈总数
            v = stackk[--top];   // v用来存出栈的数,top--,
            instack[v] = false;  //  出栈置为false,虽然对本题没多大用
        }while(u != v);  // 当出栈是u时,出栈结束
        cnt++;   // 每 一次出栈,即每一个连通图,cnt++,
    }
}

void slove()
{
    Tarjan(1);

    if(cnt == 1 && num == n)  // 如果cnt等于1,就是就一个连通图。而且连通图内的总数是n,即把每个数都连接在内了,那么久是一个连通图,满足题意
        puts("Yes");
    else
        puts("No");
}

int main()
{
    while(scanf("%d%d", &n, &m), n+m)
    {
        int a, b;
        init();

        while(m--)
        {
            scanf("%d%d", &a, &b);
            G[a].push_back(b);  // 
        }
        slove();
    }
    return 0;
}
让未来到来 让过去过去
原文地址:https://www.cnblogs.com/Tinamei/p/4705308.html