题目大意:给一个有向图的关系,判断强连通分量有且只有一个。
解题思路:模板题,直接运用Tarjan算法进行求解,最后判断强连通分量是否为一。详见code。
题目来源:http://acm.hdu.edu.cn/showproblem.php?pid=1269
code:
#include <iostream>
#include <cstdio>
#include <cstring>
#include <vector>
#include <stack>
#include <algorithm>
using namespace std;
const int MAXN = 10000+10;
const int MAXM = 100000+10;
vector<int> g[MAXN]; //存图
int pre[MAXN],lowlink[MAXN],sccno[MAXM],dfs_clock,scc_cnt;
stack<int> s;
int n,m;
void Tarjan(int u){
pre[u]=lowlink[u]=++dfs_clock; //时间戳++
s.push(u); //该点入栈
for(int i=0;i<g[u].size();i++){ //枚举每一条边
int v=g[u][i]; //邻接边
if(!pre[v]){ //未被访问
Tarjan(v); //继续向下找
lowlink[u]=min(lowlink[u],lowlink[v]);//更新结点v所能到达的最下次数层
}
else if(!sccno[v]){//如果结点在栈内
lowlink[u]=min(lowlink[u],pre[v]);
}
}
if(lowlink[u]==pre[u]){ //如果结点u是强连通分量的根
scc_cnt++; //连通分量标号++
while(!s.empty()){
int x=s.top(); //取出栈顶元素
s.pop(); //弹出栈
sccno[x]=scc_cnt; //出栈结点x属于scc_cnt标号的强连通分量
if(x==u) break;
}
}
}
void solve(){
dfs_clock=scc_cnt=0; //初始化连通分量计数器和时间戳
memset(sccno,0,sizeof(sccno)); //初始化连通分量编号数组
memset(pre,0,sizeof(pre)); //深搜次序数组
for(int i=1;i<=n;i++) //遍历寻找连通分量
if(!pre[i]) Tarjan(i); //未被访问则找i结点的连通分量
}
int main(){
int u,v;
while(scanf("%d%d",&n,&m)!=EOF && (n||m)){
for(int i=1;i<=n;i++) g[i].clear(); //使用前清空
for(int i=1;i<=m;i++){ //读入图
scanf("%d%d",&u,&v);
g[u].push_back(v);
}
solve();
if(scc_cnt==1) printf("Yes\n");
else printf("No\n");
}
return 0;
}