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.
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 ; }