Going from u to v or from v to u?
Time Limit: 2000MS | Memory Limit: 65536K | |
Total Submissions: 14474 | Accepted: 3804 |
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
题意:n个点,m条边,判断对于任意两个点u,v u能到v或者v能到u。
思路:Tarjan缩点后,判断一个有向无环图是否是一条直链即可,条件为:起点,终点只有一个,且起点出度为1或0
#include <iostream> #include <cstdio> #include <cstring> #include <vector> #include <string> #include <algorithm> #include <queue> #include <stack> using namespace std; const int maxn = 1000+10; const int maxe = 6000+10; struct edge{ int v,nxt; }e[maxe]; int head[maxn]; int n,m; stack<int> S; queue<int> que; int in[maxn],out[maxn]; int dfn[maxn],lown[maxn],sccno[maxn]; int dfs_clk,scc_cnt,nume; void init(){ dfs_clk = 0; scc_cnt = 0; nume = 1; while(!S.empty()) S.pop(); while(!que.empty()) que.pop(); memset(sccno,0,sizeof sccno); memset(dfn,0,sizeof dfn); memset(in,0,sizeof in); memset(out,0,sizeof out); memset(head,0,sizeof head); } void addedge(int u,int v){ e[++nume].nxt = head[u]; e[nume].v = v; head[u] = nume; } void Tarjan(int u){ dfn[u] = lown[u] = ++dfs_clk; S.push(u); for(int i = head[u]; i ; i = e[i].nxt){ int v = e[i].v; if(!dfn[v]){ Tarjan(v); lown[u] = min(lown[u],lown[v]); } else if(!sccno[v]){//在栈中,能到达的祖先 lown[u] = min(lown[u],dfn[v]); } } if(lown[u]==dfn[u]){ scc_cnt++; while(true){ int x = S.top();S.pop(); sccno[x] = scc_cnt; if(x==u) break; } } } int main(){ int ncase; cin >> ncase; while(ncase--){ init(); scanf("%d%d",&n,&m); int a,b; for(int i = 0; i < m; i++){ scanf("%d%d",&a,&b); addedge(a,b); } for(int i = 1; i <= n;i++){ if(!dfn[i]) Tarjan(i); } for(int i = 1; i <= n; i++){ int k = sccno[i]; for(int j = head[i]; j; j = e[j].nxt){ int d = sccno[e[j].v]; if(k!=d){ in[d]++; out[k]++; } } } int tr = 0,ts = 0; bool flag = true; for(int i = 1; i <= scc_cnt; i++){ if(in[i]==0){ tr++; if(out[i]>1){ flag = false; break; } } if(out[i]==0){ ts++; } } if(flag&&tr==1&&ts==1){ printf("Yes\n"); }else{ printf("No\n"); } } return 0; }
POJ2762-Going from u to v or from v to u?(Tarjan缩点,DAG判直链)