zoukankan      html  css  js  c++  java
  • 强连通(当模板用)——pku2186Popular Cows

    有向图强连通分量的Tarjan算法

    有个比较好的讲解http://www.byvoid.com/blog/scc-tarjan/zh-hans/

    学习一下,贴个比较好的模板

    View Code
    #include <iostream>
    #include
    <stack>
    using namespace std;

    const int MAXN = 10000 + 10; // 点的最大数量
    const int MAXM = 50000 + 10; // 边的最大数量

    // 假设对边u-->v
    struct EDGE
    {
    int v; // 从u点出发能到达的点v
    int next; // 从u点出发能到达的下一条边的编号
    };

    stack
    <int> s;
    EDGE map[MAXM];
    int low[MAXN]; // low[u]:是u或u的子树能够追溯到的最早的栈中节点的次序号
    int dfn[MAXN]; // dfn[u]:节点u搜索的次序编号(时间戳)
    int pre[MAXN]; // pre[u] = e:从点u出发的最后一条边的编号是e(“最后”是指最后输入)
    int sccf[MAXN]; // sccf[i] = j:第i个点所在的强连通分量的编号
    bool ins[MAXN]; // 是否在栈中
    int outdegree[MAXN]; // 强连通分量的出度
    int index; // 次序编号
    int scc; // 强连通分量的数目
    int n, m;

    void Tarjan(int u)
    {
    int v;
    low[u]
    = dfn[u] = index++;
    s.push(u);
    ins[u]
    = true;
    // 枚举每一条边:u-->v
    for (int k=pre[u]; k!=-1; k=map[k].next)
    {
    v
    = map[k].v;
    if (dfn[v] == 0)
    {
    Tarjan(v);
    if (low[v] < low[u])
    {
    low[u]
    = low[v];
    }
    }
    else if (ins[v] && dfn[v]<low[u])
    {
    low[u]
    = dfn[v];
    }
    }
    // 如果节点u是强连通分量的根
    if (dfn[u] == low[u])
    {
    scc
    ++;
    do
    {
    v
    = s.top();
    s.pop();
    ins[v]
    = false;
    sccf[v]
    = scc;//这里就是一个缩点的过程
    }while (u != v);
    }
    }

    void Init()
    {
    scc
    = 0;
    index
    = 1;
    memset(low,
    0, sizeof(low));
    memset(dfn,
    0, sizeof(dfn));
    memset(ins,
    false, sizeof(ins));
    memset(sccf,
    0, sizeof(sccf));
    memset(pre,
    -1, sizeof(pre));
    }

    // 获得超级受喜欢的cows的数量
    int GetSuperPopularNum()
    {
    int u, v;
    int cnt = 0; // 出度为0的强连通分量的数目
    int ct[MAXN]; // ct[i] = j:强连通分量i有j个点

    memset(outdegree,
    0, sizeof(outdegree));
    memset(ct,
    0, sizeof(ct));

    // 枚举每一个点u:求outdegree和ct
    for (u=1; u<=n; u++)
    {
    ct[sccf[u]]
    ++;
    for (int k=pre[u]; k!=-1; k=map[k].next)
    {
    // 对每条边u-->v
    v = map[k].v;
    if (sccf[u] != sccf[v])
    {
    outdegree[sccf[u]]
    ++;
    }
    }
    }
    // 数数强连通分量为0的点有多少个
    for (u=1; u<=scc; u++)
    {
    if (outdegree[u] == 0)
    {
    cnt
    ++;
    v
    = u;
    }
    }
    return (cnt == 1)? ct[v] : 0;
    }

    int main()
    {
    int i, u, v;
    int e = 0; // 边的数量,建图时会用到
    // 初始化数据并建图
    Init();
    //cin >> n >> m;
    scanf("%d%d",&n,&m);
    for (i=0; i<m; i++)
    {
    //cin >> u >> v;
    scanf("%d%d",&u,&v);
    map[e].v
    = v;
    map[e].next
    = pre[u];
    pre[u]
    = e;
    e
    ++;
    }
    // 求强连通分量
    for (i=1; i<=n; i++)
    {
    if (dfn[i] == 0)
    {
    Tarjan(i);
    }
    }
    // 输出答案
    cout << GetSuperPopularNum() << endl;
    return 0;
    }

      

  • 相关阅读:
    基于Andoird 4.2.2的同步框架源代码学习——同步发起端
    C#MD5为密码加密
    YOUYOU深入学习Ganglia之三(gmetad的软件架构)
    js原生appendChild的bug
    Spring MVC 教程,快速入门,深入分析
    Centos 6.4 Linux 相关问题总结
    jQuery插件之-瀑布流插件
    编辑简单的 shell程序
    Qt国际化相关类
    三层架构与MVC
  • 原文地址:https://www.cnblogs.com/huhuuu/p/2121148.html
Copyright © 2011-2022 走看看