题意:n个点m条单向边,问任意两个点是否连通。
总结:参考大神博客码的,有些地方还是不太明白。 而且这题还可以双向dfs做,有时间再做一下。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
// HDU-1269 #include<bits/stdc++.h> using namespace std; #pragma comment(linker, "/STACK:102400000,102400000") #define F(i,a,b) for (int i=a;i<b;i++) #define FF(i,a,b) for (int i=a;i<=b;i++) #define mes(a,b) memset(a,b,sizeof(a)) #define INF 0x3f3f3f3f typedef long long ll; const int N = 1e4+10, M = 1e5+10; int n, m, sum, top, tot; //sum为强连通分量数,top为栈指针 int head[N], Stack[N], instack[N]; //Stack[]为模拟栈,instack[]表示是否在栈中 int dfn[N], low[N], Belong[N]; //dfn[]为深搜次序数组,Low[u]为u结点或者u的子树结点所能追溯到的最早栈中结点的次序号,这两个数组是关键。Belong[]表示每个结点所对应的强连通分量标号数组,这个题里用不到 struct Edge { int to, next; } edge[M]; void Init() { sum=top=tot=0; mes(head, -1); mes(dfn, 0); } void Addedge(int u, int v) { edge[tot].to=v; edge[tot].next=head[u]; head[u]=tot++; } void Tarjan(int u) //Tarjan算法求有向图的强连通分量 { dfn[u]=low[u]=++tot; //时间戳,不太明白 Stack[top++]=u, instack[u]=1; for(int e=head[u]; e!=-1; e=edge[e].next) { int v=edge[e].to; if(dfn[v]==0) { Tarjan(v); if(low[u]>low[v]) low[u]=low[v]; //更新结点v所能到达的最小次数层,这里不太明白 } else if(instack[v] && low[u]>dfn[v]) { low[u]=dfn[v]; } } if(dfn[u]==low[u]) { //如果节点v是强连通分量的根 sum++; while(top!=0) { int t=Stack[--top]; instack[t]=0; Belong[t]=sum; if(t==u) break; //直到将v从栈中退出,这不太明白 } } } void Solve() { FF(i,1,n) if(dfn[i]==0) Tarjan(i); } int main() { while(scanf("%d%d", &n, &m)!=EOF && (n||m)) { Init(); FF(i,1,m) { int u, v; scanf("%d%d", &u, &v); Addedge(u, v); } Solve(); if(sum==1) puts("Yes"); else puts("No"); } return 0; }