您的位置:首页 > 其它

有向图的强联通分量Tarjan算法模版(hdu1269)

2015-07-19 22:03 429 查看

迷宫城堡

Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others)

Total Submission(s): 9341 Accepted Submission(s): 4170



[align=left]Problem Description[/align]
为了训练小希的方向感,Gardon建立了一座大城堡,里面有N个房间(N<=10000)和M条通道(M<=100000),每个通道都是单向的,就是说若称某通道连通了A房间和B房间,只说明可以通过这个通道由A房间到达B房间,但并不说明通过它可以由B房间到达A房间。Gardon需要请你写个程序确认一下是否任意两个房间都是相互连通的,即:对于任意的i和j,至少存在一条路径可以从房间i到房间j,也存在一条路径可以从房间j到房间i。

[align=left]Input[/align]
输入包含多组数据,输入的第一行有两个数:N和M,接下来的M行每行有两个数a和b,表示了一条通道可以从A房间来到B房间。文件最后以两个0结束。

[align=left]Output[/align]
对于输入的每组数据,如果任意两个房间都是相互连接的,输出"Yes",否则输出"No"。

[align=left]Sample Input[/align]

3 3
1 2
2 3
3 1
3 3
1 2
2 3
3 2
0 0


[align=left]Sample Output[/align]

Yes
No


[align=left]Author[/align]
Gardon

[align=left]Source[/align]
HDU 2006-4 Programming Contest

#include<iostream>
#include<cstring>
#include<cstdio>
#include<cstdlib>

using namespace std;

const int maxn = 10010;
const int maxm = 100010;

struct Edge
{
int v,next;
}edge[maxm]; //边结点数组

int first[maxn],stack[maxn],DFN[maxn],low[maxn],Belong[maxn];
/*first[]头结点数组,stack[]为栈,DFN[]为深搜次序数组,
Belong[]为每个结点所对应的强连通数组,low[u]为u结点
或者u的子树结点所能追溯到最早栈中结点的次序号
*/

int instack[maxn]; //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; //tot为时间轴
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])
{
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()
{
//freopen("1.txt","r",stdin);
while(cin>>n>>m && (n || m))
{
init();
while(m--)
{
int u,v;
cin>>u>>v;
read_graph(u,v);
}
solve(); //求强连通分量
if(scnt == 1) cout<<"Yes"<<endl;
else
cout<<"No"<<endl;
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: