繁体   English   中英

在仅通过特定节点(而不是其他节点)的正加权有向图中找到最短循环

[英]Find the shortest cycle in a positive weighted directed graph passing through only specific nodes (not the other nodes)

考虑一个加权有向图,包括 V 个顶点和 E 个边。 我正在寻找一种算法,找到通过 S 某个节点(必须通过 S 中的所有节点)而不是其他节点的最短循环。 循环从集合 S 中的节点 w 开始和结束。

是否可以删除 V - S 集合中的节点并删除它们对应的连接边,然后将算法(用于寻找最短循环)应用于此图,仅包括 S 节点及其对应的边?

我强调我们只考虑集合 S 中的节点,而不考虑其他节点。

我不确定以下链接是否与我的问题相关。 该链接要求必须通过蓝色节点的最短循环,但该循环可能会通过黑色节点(对此我不确定)。

在至少访问 X 节点一次的图中查找最短路

是的,按照您的问题陈述方式,考虑方法是正确的。

删除所有不属于集合 S 的顶点的图称为导出子图 原始图中仅使用 S 中的顶点的每个路径/循环也可以在导出子图中找到。 因此,在导出子图中寻找最短环等同于在原始图中寻找环。

如果您的问题需要找到使用 S 中所有节点的最短循环,那么您正在解决旅行商问题,该问题被称为 NP-hard,这意味着没有已知的(并且可能不存在)多项式算法。 也就是说,这是一个经过充分研究的问题,您可以从精确算法(如果集合足够小)和启发式/近似算法中进行选择,以适应更大的规模。

第一步是检测图表中存在的循环(如果有)

这可以通过修改深度优先搜索 (DFS) 来完成,如下所示:

- As the DFS proceeds through nodes, store the predecessor of each node visited
- IF a node is visited for the second time ( indicating cycle )
    - Back track through the node predeccessors, storing the reversed cycle

现在您可以过滤为您的条件检测到的周期(访问 S 中的节点、最短等)

这是检测和记录周期的 DFS 的 C++ 代码

void cGraph::dfs_cycle_detector(vertex_t start)
{
    std::vector<bool> visited(vVertex.size(), false);
    vVertex_t pred(vVertex.size(), 0);

    std::stack<vertex_t> wait;
    wait.push(start);

    while (!wait.empty())
    {
        vertex_t v = wait.top();
        wait.pop();
        int vi = findIndex(v);
        if (!visited[vi])
        {
            visited[vi] = true;

            for (vertex_t w : adjacentOut(v))
            {
                if (!visited[findIndex(w)])
                {
                    wait.push(w);
                    pred[findIndex(w)] = v;
                }
                else
                {
                    // previously visited node - a cycle
                    vVertex_t cycle;

                    cycle.push_back(w);
                    cycle.push_back(v);

                    vertex_t pv = pred[findIndex(v)];
                    cycle.push_back(pv);
                    while (pv != w)
                    {
                        // back track one hop
                        pv = pred[findIndex(pv)];
                        cycle.push_back(pv);
                    }

                    std::reverse(cycle.begin(), cycle.end());

                    // display cycle
                    std::cout << "cycle: ";
                    for (vertex_t vc : cycle)
                        std::cout << vc->userName() << " ";
                    std::cout << "\n";
                }
            }
        }
    }
}

完整的应用程序位于https://github.com/JamesBremner/graphCycler

示例 output:

node a linked to b x
node b linked to c
node c linked to d
node d linked to a
node x linked to y
node y linked to

cycle: a b c d a

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM