博客
关于我
poj 2186 Popular Cows :求能被有多少点是能被所有点到达的点 tarjan O(E)
阅读量:803 次
发布时间:2023-03-03

本文共 3601 字,大约阅读时间需要 12 分钟。

解决POJ问题2186:被所有牛崇拜的牛的数量

问题背景

在一个缩短森林(即图的强连通分量的缩影森林)中,每个缩影点代表多个原始点。问题要求找出被所有牛崇拜的牛的数量。根据问题描述,缩影点的出度为0时可能存在被所有牛崇拜的牛。具体来说,如果存在多个出度为0的缩影点,则这些点对应的牛不会互相崇拜,从而不存在被所有牛崇拜的牛。

因此,我们需要计算出出度为0的缩影点的数量,这些点对应的牛即为被所有牛崇拜的牛。

解决方案

为了解决这个问题,我们采用了基于Tarjan算法的图遍历方法,具体步骤如下:

  • 图的表示:使用邻接表表示图,其中每个节点包含其目标点和下一个边指针。

  • Tarjan算法:通过深度优先搜索(DFS)遍历图,计算每个节点的dfn( discovery time)和low值( low value),并进行强连通分量的缩影森林分析。

  • 颜色标记:将每个强连通分量中的节点赋予不同的颜色。颜色数即为强连通分量的数量。

  • 出度计算:遍历所有边,统计每个颜色类别的出度。如果某个颜色类别的出度为0,则该颜色类别的节点是出度为0的缩影点。

  • 结果计算:统计出度为0的颜色类别数量,即为被所有牛崇拜的牛的数量。如果有多个出度为0的颜色类别,则返回0,否则返回该颜色类别的节点数量。

  • 代码实现

    #include 
    #include
    #include
    using namespace std;class Graphics {private: struct Edge { int to, next; } edge[MAXM]; struct Point { int dfn, low, color; } point[MAXN]; int sign, dfnNum, colorNum, sumOfPoint, first[MAXN]; bool vis[MAXN]; stack
    stk; void tarjan(int u) { point[u].dfn = ++dfnNum; point[u].low = dfnNum; vis[u] = true; stk.push(u); for (int i = first[u]; i != -1; i = edge[i].next) { int to = edge[i].to; if (!point[to].dfn) { tarjan(to); point[u].low = min(point[to].low, point[u].low); } else if (vis[to]) { point[u].low = min(point[to].dfn, point[u].low); } } if (point[u].dfn == point[u].low) { vis[u] = false; point[u].color = ++colorNum; count[colorNum] ++; while (stk.top() != u) { vis[stk.top()] = false; point[stk.top()].color = colorNum; count[colorNum] ++; stk.pop(); } stk.pop(); } } void clear(int n) { sign = dfnNum = colorNum = 0; for (int i = 1; i <= n; ++i) { first[i] = -1; vis[i] = false; count[i] = 0; } sumOfPoint = n; while (!stk.empty()) stk.pop(); } void addEdgeOneWay(int u, int v) { if (sign >= MAXM) return; edge[sign].to = v; edge[sign].next = first[u]; first[u] = sign++; } void addEdgeTwoWay(int u, int v) { addEdgeOneWay(u, v); addEdgeOneWay(v, u); } void tarjanAllPoint() { for (int i = 1; i <= sumOfPoint; ++i) { if (!point[i].dfn) { tarjan(i); } } } int getAns() { int ans = 0, ans2 = 0; int *outdegree = new int[sumOfPoint + 1]; for (int i = 1; i <= sumOfPoint; ++i) { outdegree[i] = 0; } tarjanAllPoint(); for (int i = 1; i <= sumOfPoint; ++i) { for (int j = first[i]; j != -1; j = edge[j].next) { int to = edge[j].to; if (point[to].color != point[i].color) { outdegree[point[i].color]++; } } } for (int i = 1; i <= colorNum; ++i) { if (!outdegree[i]) { ans++; ans2 = count[i]; } } delete[] outdegree; return ans == 1 ? ans2 : 0; }};Graphics graph;int main() { int n, m; scanf("%d%d", &n, &m); graph.clear(n); while (m--) { int a, b; scanf("%d%d", &a, &b); graph.addEdgeOneWay(a, b); } printf("%d\n", graph.getAns()); return 0;}

    代码解释

  • 图的表示:使用邻接表edge数组和first数组表示图的边。first[u]记录节点u的第一个边的索引。

  • Tarjan算法tarjan(int u)函数用于进行深度优先搜索,计算节点u的dfn和low值,并进行强连通分量的缩影森林分析。

  • 颜色标记:在发现强连通分量时,赋予该分量的所有节点相同的颜色,并统计颜色数。

  • 出度计算:通过遍历所有边,统计每个颜色类别的出度。出度为0的颜色类别对应出度为0的缩影点。

  • 结果计算:统计出度为0的颜色类别数量。如果有多个,则返回0,否则返回该颜色类别的节点数。

  • 转载地址:http://uyxfk.baihongyu.com/

    你可能感兴趣的文章
    Python多处理对象引用
    查看>>
    Python多处理安全地写入文件
    查看>>
    python多处理参数:深拷贝?
    查看>>
    Python多处理使用队列写入同一个文件
    查看>>
    Python多处理.Process:从局部变量开始
    查看>>
    Python多处理-进程数
    查看>>
    python多个定时器_python单线程实现多个定时器示例
    查看>>
    python处理文本_Python - Tokenization
    查看>>
    Python处理数据方向之OpenCV
    查看>>
    python处理一亿条数据_Python数据分析实战(一)
    查看>>
    Python处理PDF神器:PyMuPDF的安装与使用
    查看>>
    Python处理Excel数据
    查看>>
    Python基础:集合与文件操作
    查看>>
    Python基础:搭建开发环境(1)
    查看>>
    PYTHON基础:如何阅读N个整数,直到#39;
    查看>>
    Python基础:11变量作用域和闭包
    查看>>
    Python基础: with模式和__enter__ 和 __exit__
    查看>>
    Python基础(7)--函数
    查看>>
    Python基础部分-while循环,格式化输出
    查看>>
    Python基础语法:顺序语句结构
    查看>>