多集最短路径算法

时间:2012-07-27 10:43:51

标签: algorithm

这是一个采访问题(我在论坛上看到它并且无法找出最佳解决方案)。问题是来自给定的一组数字找到最短的路径。

例如

Set A - [2, 14, 34]
Set B - [9, 13]
Set C - [15, 22, 62, 78]
Set D - [16, 24, 54]
Set Z - [17, 38, 41]

1)可以有任意数量的集合

2)套装内的数字永远不会重复。

3)数字可以从任何开始到任何结束(它们不在0 - n之间,即它可以从1091到1890等开始)

4)所有集合都已排序。

在上面的示例中,路径为:

B[13] -> A[14] -> C[15] -> D[16] -> Z[17]

最短路径定义为MAX数(17) - MIN数(13)= 4;

之间的差值

有什么想法吗?

5 个答案:

答案 0 :(得分:3)

制作成对列表[number,name_of_set]。对它进行排序。

对于给定长度的路径,D,扫描已排序的列表,保留2个指针。始终增加第一个指针,并在扩展大于D时增加第二个指针。扫描时,保持属于每个集合的指针之间的元素计数。如果每个集合中有元素,宾果游戏,你找到了一条差异最大​​的路径。

现在,二进制搜索D。

总体复杂度O(N log N)

答案 1 :(得分:1)

堆(优先级队列)可能会有所帮助。

  1. 合并将所有数据排序为数组N,同时保留原始集合ID,假设总共有m组;
  2. int shortest = MAX(N) - MIN(N); //即N [N.length - 1] - N [0]
  3. 初始化堆h;
  4. 使用i循环N,如果h不包含与N [i]相同的元素,则将N [i]添加到堆中;如果h已经包含来自同一组的元素,比如h [k],则将h [k]的键增加到N [i]。如果h.size()== m,则shortest == N [i] -h [0]<最短的? N [i] - h [0]:最短。
  5. 这是代码:

    mergesort(all_sets[], H, S); // H holds all data, S holds corresponding setid.
    Heap<key, setid> H = new Heap<key, setid>();
    int shortest = N[N.length - 1] - n[0];
    for(int i = 0; i < N.length; i++)
    {
       int data = N[i];
       int setID = S[i];
       int hindex = H.elementFromSet(setID);
       if(hindex < 0)
        { // H does not have any element from set with setID;
           H.add(data, setID);
        } else {
           H.increase(data, hindex);
        }
        if(H.size() == m)
        {
           shortest = shortest > N[i] - H[0]? N[i] - H[0] : shortest;
        }
    }
    

    也许我可以使用哈希表来跟踪set id到堆索引。

    运行时我认为 O(nlgm)

答案 2 :(得分:0)

  1. 取A组和B组。找到此集合中的最短路径。 这将是14-13。现在对它进行排序,使其变为13-14。 现在短集短= {13,14}

  2. 选择短集{13,14}并设置C {15,22,62,78}。 现在,起始节点为13,短节点中的结束节点为14。 从端节点14开始,最短可到达路径是15。 所以将15添加到短集。 现在短集变为{13,14,15},对其进行排序以使其保持{13,14,15}

  3. 现在选择短集{13,14,15}并设置D {16,24,54} 短集中的结束节点是15.所以我们从那里开始。 现在从25到D的最短路径是16.因此在短集合中加16。 现在短集变为{13,14,15,16}。解决 。它仍然是{13,14,15,16}

  4. 3。我们可以对整个集合重复这一点,以得到结果的短集。

答案 3 :(得分:0)

您可以应用与我描述的算法in this question基本相同的想法。

让我们寻找最后一个子集的中心。它必须最小化到每个组的最大距离。像往常一样,点到集合的距离定义为点与集合元素之间的最小距离。

对于每个集合i,描述到集合距离的函数fi是分段线性的。如果a,b是两个连续的数字,则关系fi(a) = 0, fi((a+b)/2) = (b-a)/2, fi(b) = 0让我们在线性时间内构建所有fi的描述。

但我们也可以通过考虑线性时间的连续区间[a,b]来计算线性时间内两个分段函数fifj的最大值:结果是线性的,或者通过将函数的唯一交叉点添加到分区来分段线性。由于函数的斜率总是+1或-1,因此交点是半整数,因此可以用浮点(或定点)算法精确表示。

凸性参数显示所有g的最大fi最多只能获得fi的两倍,所以我们不必担心最多具有多个点数,这些点在集合数量中呈指数级。

所以我们只是:

  1. 计算fi的分段线性距离函数i = 1..p
  2. 通过重复计算最大值来计算所有g的最大fi
  3. g的任何最小点的位置是所需的中心。
  4. 对于每一组,选择距离中心最近的点。
  5. 我们选择的点集的宽度恰好是g的最小值: - )
  6. 如果集合数量有限,复杂度为O( N ),如果集合数量 p ,则复杂度为O( N p )是可变的。通过聪明地计算你如何计算最大值(分而治之),我认为你甚至可以将它减少到O( N log p )。

答案 4 :(得分:0)

这是问题的另一种表述。

问:找出包含所有集合中元素的最小间隔。

答:

  1. 将所有元素放在一个存储桶中并对其进行排序。复杂度O(N * K)
  2. 我们将找到最大的数字,使得每个集合中至少有一个元素通过二进制搜索高于此数字。这将是MIN。
  3. 类似地,找到最小的数字,使得每个集合中至少有一个元素通过二分搜索小于该数字。这将是MAX。
  4. 作为优化,您可以将每个集存储为间隔,并在步骤2和3中使用间隔树进行查询。这样,查询复杂度从O(K)变为O(log K)