题意当强连通分量为1的时候输出Yes否者输出No。
学习了一下强连通分量的步骤,给出算法详解http://www.byvoid.com/zht/blog/scc-tarjan(注:不能用IE浏览)
该题也可以用双向dfs求强连通分量,这里给出Tarjan算法的模板,更适合变形。
也贴上双向dfs的代码吧。
代码Tarjan(这是网上有注释的代码,讲得很细):
#include <iostream> #include <cstring> #include <cstdio> #include <cstdlib> using namespace std; #define MAXN 10010 #define MAXM 100010 struct Edge { int v, next; }edge[MAXM]; //边结点数组 int first[MAXN], stack[MAXN], DFN[MAXN], Low[MAXN], Belong[MAXM]; // first[]头结点数组,stack[]为栈,DFN[]为深搜次序数组,Belong[]为每个结点所对应的强连通分量标号数组 // Low[u]为u结点或者u的子树结点所能追溯到的最早栈中结点的次序号 int instack[10010]; // instack[]为是否在栈中的标记数组 int n, m, cnt, scnt, top, tot; void init() { cnt = 0; scnt = top = tot = 0; //初始化连通分量标号,次序计数器,栈顶指针为0 memset(first, -1, sizeof(first)); memset(DFN, 0, sizeof(DFN)); //结点搜索的次序编号数组为0,同时可以当是否访问的数组使用 } void read_graph(int u, int v) //构建邻接表 { edge[tot].v = v; edge[tot].next = first[u]; first[u] = tot++; } void Tarjan(int v) //Tarjan算法求有向图的强连通分量 { int min, t; DFN[v] = Low[v] = ++tot; //cnt为时间戳 instack[v] = 1; //标记在栈中 stack[top++] = v; //入栈 for(int e = first[v]; e != -1; e = edge[e].next) { //枚举v的每一条边 int j = edge[e].v; //v所邻接的边 if(!DFN[j]) { //未被访问 Tarjan(j); //继续向下找 if(Low[v] > Low[j]) Low[v] = Low[j]; // 更新结点v所能到达的最小次数层 } else if(instack[j] && DFN[j] < Low[v]) { //如果j结点在栈内, Low[v] = DFN[j]; } } if(DFN[v] == Low[v]) { //如果节点v是强连通分量的根 scnt++; //连通分量标号加1 do { t = stack[--top]; //退栈 instack[t] = 0; //标记不在栈中 Belong[t] = scnt; //出栈结点t属于cnt标号的强连通分量 }while(t != v); //直到将v从栈中退出 } } void solve() { for(int i = 1; i <= n; i++) //枚举每个结点,搜索连通分量 if(!DFN[i]) //未被访问 Tarjan(i); //则找i结点的连通分量 } int main() { while(scanf("%d%d",&n,&m) && (n || m)) { init(); while(m--) { int u, v; scanf("%d%d", &u, &v); read_graph(u, v); } solve(); //求强连通分量 if(scnt == 1) printf("Yes\n"); //只有一个强连通分量,说明此图各个结点都可达 else printf("No\n"); } return 0; }
双向DFS:
#include<iostream> #include<cstring> using namespace std; const int N=10010; const int M=100010; struct Edge { int v,next; }edge1[M],edge2[M]; int vis1[N],vis2[N]; int tot1,tot2; int first1[N],first2[N]; int num[N]; int cn,ans; int belong[N]; int a,b,n,m,j; void init() { ans=0;tot1=tot2=0;cn=0; memset(first1,-1,sizeof(first1)); memset(first2,-1,sizeof(first2)); memset(vis1,0,sizeof(vis1)); memset(vis2,0,sizeof(vis2)); } void add_edge(int a,int b) { tot1++; edge1[tot1].v=b; edge1[tot1].next=first1[a]; first1[a]=tot1; tot2++; edge2[tot2].v=a; edge2[tot2].next=first2[b]; first2[b]=tot2; } void DFS_1(int v) { vis1[v]=1; for(int i=first1[v];i!=-1;i=edge1[i].next) { if(!vis1[edge1[i].v]) DFS_1(edge1[i].v); } num[cn++]=v; } void DFS_2(int v) { vis2[v]=1; for(int i=first2[v];i!=-1;i=edge2[i].next) { if(!vis2[edge2[i].v]) DFS_2(edge2[i].v); } } int main() { while(cin>>n>>m,n||m) { init(); for(int i=0;i<m;i++) { cin>>a>>b; add_edge(a,b); } for(int i=1;i<=n;i++) { if(!vis1[i]) { DFS_1(i); } } for(int i=cn-1;i>=0;i--) { if(!vis2[num[i]]) { DFS_2(num[i]); ans++; } } if(ans==1) cout<<"Yes"<<endl; else cout<<"No"<<endl; } return 0; }