强连通分量


感觉挺有趣的,就谢了已发,其实就是判断这个有向图是否两两连通。。。。。

解释就是这个博客上的tarjan算法

我实现后代码如下。。。

#include <stdio.h>
#include <string.h>
#include <vector>
#include <stack>
#include <algorithm>
using namespace std;
#define N 10005
stack<int>sta;
vector<int>mp[N];
int dfn[N];
int low[N];
int InStack[N];
int indexx,number;
int n, m;

void tarjan(int u)
{
	InStack[u] = 1;
	low[u] = dfn[u] = ++ indexx;
	sta.push(u);

	for (int i = 0; i < mp[u].size(); ++ i)
	{
		int t = mp[u][i];
		if (dfn[t] == 0)//如果没有入过栈内,
		{
			tarjan(t);//把他遍历一边
			low[u] = min(low[u], low[t]);//遍历完之后寻找他的子节点中low最小的
		}
		else if (InStack[t] == 1)//如果他的某个节点在栈中,
		{	
			low[u] = min(low[u], dfn[t]);//最早的时间戳就是他的所有子节点的最早时间
		}
	}

	if (low[u] == dfn[u])//如果找到这两个时间戳相等,那么这个点是此联通图的开始那个点,退栈到u=v
	{
		++ number;//表示有几个强连通图
		while (!sta.empty())
		{
			int v = sta.top();
			sta.pop();
			InStack[v] = 0;//把它标记为未在栈内
			if (v == u)
				break;
		}
	}
}

int main()
{
    //freopen("input.txt","r",stdin);
    while(scanf("%d%d",&n,&m),n+m)
    {
	memset(dfn, 0, sizeof(dfn));
	memset(low, 0, sizeof(low));
	memset(InStack, 0, sizeof(InStack));
	indexx = number = 0;
	for (int i = 1; i <= n; ++ i)
	{
		mp[i].clear();
	}
	while(!sta.empty())
		sta.pop();
    for(int i=1;i<=m;i++)
    {
        int a,b;
        scanf("%d%d",&a,&b);
        mp[a].push_back(b);
    }
    for(int i=1;i<=n;i++)
        if(!dfn[i])
            tarjan(i);
    if(number>1)//如果有多个连通图的话,那么此有向图肯定不是点两两连通
        puts("No");
    else
        puts("Yes");
    }
}

强连通分量_第1张图片

上图就是最后处理好之后的low  和dfn的值

比较注意的是3   4  的值

因为  自己手动模拟一下  匾额发现其中的奥秘

你可能感兴趣的:(强连通分量)