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

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 ;

}



你可能感兴趣的:(tar)