• POJ 2762 Going from u to v or from v to u? (Tarjan)


    Description

    In order to make their sons brave, Jiajia and Wind take them to a big cave. The cave has n rooms, and one-way corridors connecting some rooms. Each time, Wind choose two rooms x and y, and ask one of their little sons go from one to the other. The son can either go from x to y, or from y to x. Wind promised that her tasks are all possible, but she actually doesn't know how to decide if a task is possible. To make her life easier, Jiajia decided to choose a cave in which every pair of rooms is a possible task. Given a cave, can you tell Jiajia whether Wind can randomly choose two rooms without worrying about anything?

    Input

    The first line contains a single integer T, the number of test cases. And followed T cases. 

    The first line for each case contains two integers n, m(0 < n < 1001,m < 6000), the number of rooms and corridors in the cave. The next m lines each contains two integers u and v, indicating that there is a corridor connecting room u and room v directly. 

    Output

    The output should contain T lines. Write 'Yes' if the cave has the property stated above, or 'No' otherwise.

    Sample Input

    1
    3 3
    1 2
    2 3
    3 1
    

    Sample Output

    Yes
       题目大意:给你一个有向图,让你判断任意两个顶点 u和v 之间是否存在可达的路径,即 u可以到达v 或 v 可以到达 u 。
       解题思路:先用tarjan缩点,然后用拓扑排序一下,排序后的序列中,如果所有相邻两个点之间均存在边,则说明原图中,任意两点之间均存在可达的路径,即输出“Yes”,否则,输出“No”。
       请看代码:
    #include<iostream>
    #include<cstring>
    #include<string>
    #include<cmath>
    #include<cstdio>
    #include<algorithm>
    using namespace std ;
    const int MAXN = 1111 ;
    struct Node
    {
        int adj ;
        Node *next ;
    }mem[MAXN * 6]; // 先把存放边节点的数组开好,这样能大量节省时间
    int memp ;
    Node *vert[MAXN] ; // 建立顶点数组
    short g[MAXN][MAXN] ; // 缩点后的邻接矩阵
    bool inq[MAXN] ; // 判断节点是否在栈中
    int stap[MAXN] ; // 数组模拟栈
    int top ;
    int d[MAXN] ;  // 统计 缩点后各连通分量的 入度
    int tpo[MAXN] ;  // 拓扑序列
    bool vis[MAXN] ;
    int dfn[MAXN] ;
    int low[MAXN] ;
    int tmpdfn ;
    int belong[MAXN] ;
    int n , m ;
    int scnt ;  // 记录强连通分量个数
    void clr() // 初始化
    {
        memset(dfn , 0 , sizeof(dfn)) ;
        memset(low , 0 , sizeof(low)) ;
        memset(vert , 0 , sizeof(vert)) ;
        memset(belong , -1 , sizeof(belong)) ;
        memset(vis , 0 , sizeof(vis)) ;
        memset(g , 0 , sizeof(g)) ;
        memset(stap , -1 , sizeof(stap)) ;
        memset(d , 0 , sizeof(d)) ;
        memset(tpo , -1 , sizeof(tpo)) ;
        memset(inq , 0 , sizeof(inq)) ;
        memp = 0 ;
        top = -1 ;
        scnt = -1 ;
        tmpdfn = 0 ;
    }
    void tarjan(int u)
    {
        vis[u] = 1 ;
        dfn[u] = low[u] = ++ tmpdfn ;
        stap[++ top] = u ;
        inq[u] = true ;
        Node *p = vert[u] ;
        while (p != NULL)
        {
            int v = p -> adj ;
            if(!vis[v])
            {
                tarjan(v) ;
                low[u] = min(low[u] , low[v]) ;
            }
            else if(inq[v])  // 如果点v还在栈中
            {
                low[u] = min(low[u] , dfn[v]) ;
            }
            p = p -> next ;
        }
        if(dfn[u] == low[u])  // 缩点
        {
            scnt ++ ;
            int tmp = stap[top --] ;
            do
            {
                tmp = stap[top --] ;
                inq[tmp] = false ;
                belong[tmp] = scnt ;
            }while(tmp != u) ;
        }
    }
    void build()
    {
        Node * p ;
        int i ;
        for(i = 1 ; i <= n ; i ++)
        {
            p = vert[i] ;
            while (p)
            {
                int tv = p -> adj ;
                int x = belong[i] ;
                int y = belong[tv] ;
                g[belong[i]][belong[tv]] = 1 ;
                if(x != y)
                    d[y] ++ ;
                p = p -> next ;
            }
        }
    }
    void topo()  // 拓扑排序
    {
        int k ;
        for(k = 0 ; k <= scnt ; k ++)
        {
            int i ;
            for(i = 0 ; i <= scnt ; i ++)
            {
                if(d[i] == 0)
                    break ;
            }
            tpo[k] = i ;
            d[i] = -1 ;
            int j ;
            for(j = 0 ; j <= scnt ; j ++)
            {
                if(i != j)
                    d[j] -= g[i][j] ;
            }
        }
    }
    void init()
    {
        scanf("%d%d" , &n , &m) ;
        int i , j ;
        clr() ;
        int root ;
        for(i = 0 ; i < m ; i ++)
        {
            int a , b ;
            scanf("%d%d" , &a , &b) ;
            Node *p = &mem[memp] ;
            p -> adj = b ;
            p -> next = vert[a] ;
            vert[a] = p ;
    
            memp ++ ;
        }
        for(i = 1 ; i <= n ; i ++)  // 注意此处,保证图中每个节点都被访问
        {
            if(!vis[i])
            tarjan(i) ;
        }
        build() ;
        topo() ;
        bool flag = true ;
        for(i = 0 ; i < scnt ; i ++)
        {
            if(!g[ tpo[i] ][ tpo[i + 1] ])
            {
                flag = false ;
                break ;
            }
        }
        if(flag)
            puts("Yes") ;
        else
            puts("No") ;
    }
    int main()
    {
        int T ;
        scanf("%d" , &T) ;
        while (T --)
        {
            init() ;
        }
        return 0 ;
    }
    


  • 相关阅读:
    实战练习6—水波纹制作
    实战练习5—冰块中的效果
    实战练习4—逼真眼泪
    5、选择工具&描边
    实战练习3-修饰服装皱褶
    实战练习2—方块
    实战练习1—照片的局部放大
    23、裁剪
    iOS 处理第三方SDK冲突问题
    iOS 修改启动图无效
  • 原文地址:https://www.cnblogs.com/riskyer/p/3257988.html
Copyright © 2020-2023  润新知