Going from u to v or from v to u?
Time Limit: 2000MS | Memory Limit: 65536K | |
Total Submissions: 12260 | Accepted: 3139 |
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
Source
POJ Monthly--2006.02.26,zgl & twb
题意:有N个山洞m条路,问任意两点x y 能否存在从x到y 或者从y到x。
思路:注意是或 而不是和。所以缩点后,不是判断强连通为1。
第一种方法:从入度为0的点 DFS 搜索 最长能到达的路径 如果路径长度等于点数,说明可以从源点访问完所有点。
思路:注意是或 而不是和。所以缩点后,不是判断强连通为1。
第一种方法:从入度为0的点 DFS 搜索 最长能到达的路径 如果路径长度等于点数,说明可以从源点访问完所有点。
#include<iostream> #include<cstdio> #include<cstring> using namespace std; const int VM=1010; const int EM=6010; struct Edge{ int to,nxt; }edge1[EM],edge2[EM]; int n,m,cnt,dep,top,atype,head1[VM],head2[VM]; int dfn[VM],low[VM],vis[VM],indeg[VM],outdeg[VM],belong[VM]; int stack[VM]; void Init(){ cnt=0, dep=0, top=0, atype=0; memset(head1,-1,sizeof(head1)); memset(head2,-1,sizeof(head2)); memset(dfn,0,sizeof(dfn)); memset(low,0,sizeof(low)); memset(vis,0,sizeof(vis)); memset(indeg,0,sizeof(indeg)); memset(outdeg,0,sizeof(outdeg)); memset(belong,0,sizeof(belong)); } void addedge(int cu,int cv,Edge edge[],int head[]){ edge[cnt].to=cv; edge[cnt].nxt=head[cu]; head[cu]=cnt++; } void Tarjan(int u){ dfn[u]=low[u]=++dep; stack[top++]=u; vis[u]=1; for(int i=head1[u];i!=-1;i=edge1[i].nxt){ int v=edge1[i].to; if(!dfn[v]){ Tarjan(v); low[u]=min(low[u],low[v]); }else if(vis[v]) low[u]=min(low[u],dfn[v]); } int j; if(dfn[u]==low[u]){ atype++; do{ j=stack[--top]; belong[j]=atype; vis[j]=0; }while(j!=u); } } int path[VM],maxdep; void DFS(int u,int d){ path[u]=d; maxdep=max(maxdep,d); for(int i=head2[u];i!=-1;i=edge2[i].nxt){ int v=edge2[i].to; if(path[u]>path[v]) DFS(v,d+1); } } int Solve(){ int u,v; for(u=1;u<=n;u++) for(int i=head1[u];i!=-1;i=edge1[i].nxt){ v=edge1[i].to; if(belong[u]!=belong[v]){ indeg[belong[v]]++; addedge(belong[u],belong[v],edge2,head2); } } maxdep=0; for(u=1;u<=n;u++) if(!indeg[u]){ DFS(u,1); break; } if(maxdep==atype) return 1; return 0; } int main(){ //freopen("input.txt","r",stdin); int t; scanf("%d",&t); while(t--){ Init(); scanf("%d%d",&n,&m); int u,v; while(m--){ scanf("%d%d",&u,&v); addedge(u,v,edge1,head1); } for(int i=1;i<=n;i++) if(!dfn[i]) Tarjan(i); if(Solve()) printf("Yes\n"); else printf("No\n"); } return 0; }
第二种方法: 只要用拓扑判断入度为0的点是否为1个,如果有多个,就出现在分叉,不可能从x到y。
#include <stdio.h> #include <string.h> #define VM 1005 #define EM 6005 struct E { int to,next; }edge[EM]; struct E1 { int frm,to,next; }edge1[EM]; int head[VM],head1[VM],indeg[VM],map[VM][VM]; int dfn[VM],low[VM],vis[VM],belong[VM],stack[VM]; int scc,cnt,top,p,n; void addedge (int cu,int cv) { edge[p].to = cv; edge[p].next = head[cu]; head[cu] = p++; } void addedge1(int cu,int cv) { edge1[p].frm = cu; edge1[p].to = cv; edge1[p].next = head1[cu]; head1[cu] = p ++; } void tarjan (int u) { int v; dfn[u] = low[u] = ++cnt; stack[top++] = u; vis[u] = 1; for (int i = head[u];i != -1;i = edge[i].next) { v = edge[i].to; if (!dfn[v]) { tarjan(v); low[u] = low[u] > low[v]?low[v]:low[u]; } else if (vis[v]&&low[u] > dfn[v]) low[u] = dfn[v]; } if (dfn[u] == low[u]) { ++scc; do { v = stack[--top]; vis[v] = 0; belong[v] = scc; } while (u != v); } } void sovle () { int u; scc = top = cnt = 0; memset (dfn,0,sizeof(dfn)); memset (vis,0,sizeof(vis)); for (u = 1;u <= n;u ++) if (!dfn[u]) tarjan(u); } int topo () { int u,v,i,cur,count = 0;; for (u = 1;u <= scc;u ++) if (!indeg[u]) { count ++; cur = u; } if (count > 1) return 0; int num = scc; while (num --) { count = 0; for (i = head1[cur];i != -1;i = edge1[i].next) { u = edge1[i].frm; v = edge1[i].to; //indeg[u] --; indeg[v] --; if (!indeg[v]) { count ++; cur = v; } } if (count > 1) return 0; } return 1; } int ans() { int u,v,i,count = 0; memset (indeg,0,sizeof(indeg)); memset (map,0,sizeof (map)); for (u = 1;u <= n;u ++) for (i = head[u];i != -1;i = edge[i].next) { v = edge[i].to; int j,k; j = belong[u]; k = belong[v]; if (j != k&& !map[j][k]) { indeg[k] ++; addedge1 (j,k); map[j][k] = 1; } } if (topo()) return 1; return 0; } int main () { int t,m,u,v; scanf ("%d",&t); while (t --) { p = 0; memset (head1,-1,sizeof(head1)); memset (head,-1,sizeof(head)); scanf ("%d%d",&n,&m); while (m --) { scanf ("%d%d",&u,&v); addedge (u,v); } sovle (); if (ans()) printf ("Yes\n"); else printf("No\n"); } return 0; }