/*该题被博客里标记为中等题,30分钟内1A,掌握了算法就简单了,单向连通图判定,单向连通图缩点 后必然唯一存在出度为0的点和入度为0的点,并且从入度为0的点出发,可以遍历所有点后到达出度为0点 (一条长链),(容易反证),所以缩点后,我重新建图(以前觉得重新建图好麻烦,现在看来SO easy), ,对新有向无环图,从入度为0的点做dfs(回溯时要标记回来,因为要所有dfs路线),有一条深度到达 强连通分支数即为yes,反之no*/ #include<iostream> //297MS, 1A,简单题。 #include<vector> #include<cstdio> #include<cstring> #include<stack> using namespace std; int n;int m; const int MAX=1001; vector<vector<int> >edges(MAX); //原图 vector<vector<int> >newedge(MAX);//缩点后图 int visited[MAX]; //原图tarjan int low[MAX]; int dfn[MAX]; bool mark[MAX]; //新图dfs标记 int Strongly_connected_branch[MAX]; //并为一个强连通,标记为1.2.3... int num;int times; stack<int>s; bool instack[MAX]; int ind[MAX]; //入度数组 void tarjan(int u) { low[u]=dfn[u]=times++; instack[u]=1; s.push(u); int len=edges[u].size(); for(int i=0;i<len;i++) { int v=edges[u][i]; if(visited[v]==0) { visited[v]=1; tarjan(v); if(low[u]>low[v])low[u]=low[v]; } else if(instack[v]&&low[u]>dfn[v]) //有向图,要问是否在栈中,后向边,V为U某个祖先 { low[u]=dfn[v]; } } if(dfn[u]==low[u]) //在一个SCC { num++;int temp; do { temp=s.top(); instack[temp]=0; s.pop(); Strongly_connected_branch[temp]=num; } while(temp!=u); } } bool is_no; void dfs(int u,int depth) //新图的dfs { if(depth==num)is_no=true; int len=newedge[u].size(); for(int i=0;i<len;i++) { int v=newedge[u][i]; if(mark[v]==0) { mark[v]=1; dfs(v,depth+1); mark[v]=0; } } } void readin() { scanf("%d%d",&n,&m); int from,to; for(int i=1;i<=m;i++) { scanf("%d%d",&from,&to); edges[from].push_back(to); } } void initialize() //初始化 { is_no=num=times=0; for(int i=0;i<=n;i++) { ind[i]=0; mark[i]=instack[i]=low[i]=dfn[i]=visited[i]=0; edges[i].clear(); newedge[i].clear(); Strongly_connected_branch[i]=-1; } } void solve() { for(int i=1;i<=n;i++) if(visited[i]==0) { visited[i]=1; tarjan(i); } for(int i=1;i<=n;i++) //重新建图,不在同一个SCB的边留下即可。 { int len=edges[i].size(); for(int j=0;j<len;j++) { int v=edges[i][j]; if(Strongly_connected_branch[v]!=Strongly_connected_branch[i]) //注意用SCB序号作代表元(新节点)来重新建图 { ind[Strongly_connected_branch[v]]++; newedge[Strongly_connected_branch[i]].push_back(Strongly_connected_branch[v]); } } } int is_0ind; for(int i=1;i<=num;i++) //找到入度为0的点,做起点dfs { if(ind[i]==0)is_0ind=i; } mark[is_0ind]=1; dfs(is_0ind,1); if(is_no)printf("Yes "); else printf("No "); } int main() { int tcase; scanf("%d",&tcase); while(tcase--) { initialize(); readin(); solve(); } return 0; }