博客
关于我
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/

    你可能感兴趣的文章
    PyCharm 数据库操作详解
    查看>>
    PyCharm 版本与管理详解
    查看>>
    PyCharm 界面排版详解
    查看>>
    pycharm 配置qt
    查看>>
    Pycharm+Django搭建第一个Python Web程序
    查看>>
    pycharm+pyqt5配置
    查看>>
    PyCharm不突出显示错误
    查看>>
    pycharm中windows找不到chrome解决办法
    查看>>
    Pycharm中基于Ollama和Proxy AI使用本地算力进行AI辅助编程
    查看>>
    Pycharm中配置项目的打开方式(This Window,New Window)
    查看>>
    PyCharm为什么这么牛?
    查看>>
    Pycharm出现 Cannot find declaration to go to 解决方法(全)
    查看>>
    pycharm出现Can‘t get remote credentials for deployment server 的解决方法
    查看>>
    pycharm可视化数据库
    查看>>
    pytorch 中的 #@save的意思
    查看>>
    Pycharm如何取消自动换行
    查看>>
    PyCharm安装及使用说明
    查看>>
    pycharm导入自己写的模块时,模块下方出现红色波浪线的解决方案
    查看>>
    Pycharm常用快捷键大全
    查看>>
    PyCharm快捷键
    查看>>