找到加权重叠区间的最高加权重的区间的算法

时间:2014-03-30 18:49:14

标签: algorithm

嗯,我觉得很难解释,所以我已经做了一个数字来表明这一点。

正如我们在该图中所看到的,有6个时间间隔。每个人都有自己的体重。不透明度越高,重量越高。我想要一个算法来找到具有最高总重量的区间。在图的情况下,它是间隔5和6的重叠,这是不透明度最高的区域。

2 个答案:

答案 0 :(得分:5)

  • 将每个间隔分成开始点和结束点。

  • 对点进行排序。

  • 以0的总和开始。

  • 使用sweep-line algorithm

    迭代这些点
    • 如果你有一个起点:

      • 将总和增加相应间隔的值。

      • 如果总和数高于目前为止的最佳总和,请存储此起点并设置一个标志。

    • 如果你得到一个终点:

      • 如果设置了该标志,则存储存储的起点和此终点,并将当前总和作为最佳间隔,并重置该标志。

      • 将计数减去相应间隔的值。

这是源自the answer I wrote here,它基于未加权版本,即找到重叠间隔的最大数量,而不是最大总重量。

示例:

对于这个例子:

起点/终点的排序方式为:(S = start,E = end)

1S, 1E, 2S, 3S, 2E, 3E, 4S, 5S, 4E, 6S, 5E, 6E

通过它们进行迭代,您可以在1S5S6S上设置标记,然后将相应的区间存储在1E4E5E(这是您在上述起点之后获得的第一个终点)。

您不会在2S3S4S上设置标记,因为总和将低于目前为止的最佳总和。

答案 1 :(得分:1)

算法逻辑可以从图中导出。假设时间间隔的分辨率为1分钟,则可以创建一个数组并用于所有计算:

  1. 创建24 * 60个元素的数组,并用0个权重填充;
  2. 对于每个时间间隔,将此间隔的权重添加到数组的相应部分;
  3. 通过迭代数组找到最大总重量;
  4. 再次遍历数组并输出具有最大总重量的数组索引(时间)。
  5. 如果您需要在输出中包含区间索引,则可以针对略有不同的任务修改此算法。在这种情况下,数组应该包含输入时间间隔索引的列表作为第二个维度(或者它可以是一个单独的数组,具体取决于特定的语言)。

    UPD。我很好奇这个简单的算法是否比@Dukeling建议的更优雅的算法慢得多。我编写了两种算法并创建了一个输入生成器来估计它们的性能。

    发电机:

    #!/bin/sh
    awk -v n=$1 '
    BEGIN {
      tmax = 24 * 60; wmax = 100;
      for (i = 0; i < n; i++) {
        t1 = int(rand() * tmax);
        t2 = int(rand() * tmax);
        w  = int(rand() * wmax);
        if (t2 >= t1) {print t1, t2, w} else {print t2, t1, w}
      }
    }' | sort -n > i.txt
    

    算法#1:

    #!/bin/sh
    awk '
    {t1[++i] = $1; t2[i] = $2; w[i] = $3}
    END {
      for (i in t1) {
        for (t = t1[i]; t <= t2[i]; t++) {
          W[t] += w[i];
        }
      }
      Wmax = 0.;
      for (t in W){
        if (W[t] > Wmax) {Wmax = W[t]}
      }
      print Wmax;
      for (t in W){
        if (W[t] == Wmax) {print t}
      }
    }
    ' i.txt > a1.txt
    

    算法#2:

    #!/bin/sh
    awk '
    {t1[++i] = $1; t2[i] = $2; w[i] = $3}
    END {
      for (i in t1) {
        p[t1[i] "a" i] = i "S";
        p[t2[i] "b" i] = i "E";
      }
      n = asorti(p, psorted, "@ind_num_asc");
      W = 0.; Wmax = 0.; f = 0;
      for (i = 1; i <= n; i++){
        P = p[psorted[i] ];
        k = int(P);
        if (index(P, "S") > 0) {
          W += w[k];
          if (W > Wmax) {
            f = 1;
            Wmax = W;
            to1 = t1[k]
          }
        }
        else {
          if (f != 0) {
            to2 = t2[k];
            f = 0
          }
          W -= w[k];
        }
      }
      print Wmax, to1 "-" to2
    }
    ' i.txt > a2.txt
    

    结果:

    $ ./gen.sh 1000
    $ time ./a1.sh
    real    0m0.283s
    $ time ./a2.sh
    real    0m0.019s
    $ cat a1.txt
    24618
    757
    $ cat a2.txt
    24618 757-757
    $ ./gen.sh 10000
    $ time ./a1.sh
    real    0m3.026s
    $ time ./a2.sh
    real    0m0.144s
    $ cat a1.txt
    252452
    746
    $ cat a2.txt
    252452 746-746
    $ ./gen.sh 100000
    $ time ./a1.sh
    real    0m34.127s
    $ time ./a2.sh
    real    0m1.999s
    $ cat a1.txt
    2484719
    714
    $ cat a2.txt
    2484719 714-714
    

    简单的开启速度要慢20倍。