POJ 2186(有向图的强连通分量Tarjan)

首先转载ByVoid大神的日志一篇:http://www.byvoid.com/blog/scc-tarjan/

这个可以说是我看过最好的讲解tarjian算法的文章了,实例分析,带图片,非常有助于理解,这里请允许我代表我本人以及看过我的这篇博文的读者向THU ByVoid大神致以崇高的敬意!

下面转入正题,本题可以说是很明显的tarjian算法题目,如果说看不出来,这里提供一篇日志:http://blog.csdn.net/lyy289065406/article/details/6764104

不懂的看看这个就应该明白为什么用tarjian求strong connect component可以解决这个了。

基于以上两篇文章,我认为我没有任何必要写解题思路了:

不过,解决本体,有一个地方,很多人说,缩图之后进行dfs判断,其实这个是不需要的,只要记录所图后每个点的出度即可,如果出度为0的点>1,那么就可能没有形成树,或者即使形成树,但是叶子节点>1.所以答案为0.大家仔细想想,这样处理是肯定正确的。


下面是代码:

#include <cstdio>
#include <stack>
#include <cstring>
#include <iostream>
#include <vector>
#define maxn 10007
using namespace std;

int n, m, be[maxn], dfn[maxn], low[maxn];
int sum, t, in[maxn], out[maxn], ans;
bool v[maxn];
vector<int> e[maxn];
stack<int> stk;

void tarjan( int s )
{
    int i, j;
    dfn[s] = low[s] = ++t;
    v[s] = true;
    stk.push(s);
    for ( i = 0; i < e[s].size(); i++ )
    {
        j = e[s][i];
        if ( !dfn[j] )
        {
            tarjan(j);
            if (low[s]>low[j]) low[s] = low[j];
        }
        else if ( v[j] && dfn[j]<low[s] )
            low[s] = dfn[j];
    }
    if ( dfn[s]==low[s] )
    {
        do
        {
            j = stk.top();
            v[j] = false;
            be[j] = sum;
            stk.pop();
        }
        while ( j != s );
        sum++;
    }
}

int main()
{
    int i, j, k, a, b;
    cin >> n >> m;
    while ( !stk.empty() ) stk.pop();
    for ( i = 0; i < n; i++ )
        e[i].clear();
    for ( i = 0; i < m; i++ )
    {
        scanf( "%d%d", &a, &b);
        a--; b--;
        e[a].push_back(b);
    }
    memset(dfn,0,sizeof(dfn));
    memset(v,0,sizeof(v));
    sum = t = 0;
    for ( i = 0; i < n; i++ )
        if ( !dfn[i] ) tarjan(i);

    memset(in,0,sizeof(in));
    memset(out,0,sizeof(out));
    for ( i = 0; i < n; i++ )
    for ( j = 0; j < e[i].size(); j++ )
        if ( be[e[i][j]] != be[i] )
        {
            out[be[i]]++; in[be[e[i][j]]];
        }
    k = -1; ans = 0;
    for ( i = 0; i < sum; i++ )
    if ( out[i] == 0 )
    {
        if ( k != -1 ) break;
        k = i;
    }
    if ( i < sum ) { printf( "0\n"); return 0; }
    for ( i = 0; i < n; i++ )
        if ( be[i] == k ) ans++;
    printf( "%d\n", ans);
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值