以最低成本找到建筑物的共同高度

时间:2012-09-24 06:27:44

标签: algorithm

这是一些编程竞赛的问题(我不确切知道它属于哪个编程竞赛,我在一年前看到过)。问题如下:

有N栋建筑物,每栋建筑物都有自己的高度(不一定是唯一的)

{h1,h2,h3,...,hn}

我们必须让所有相同高度的建筑物都说h。

允许的操作是:

  1. 我们可以为建筑增加一些高度。
  2. 我们可以从建筑物中移除一些高度。
  3. 每个建筑物都需要相关费用来移除/添加单位高度。假设c(i)是移除/增加建筑物单位高度的成本。各自的费用如下:

    {c1,c2,c3,...,cn}
    

    假设我们有足够的高度(单位),我们必须找到使所有建筑物具有相同高度所需的最低成本。

    输入: 第一行将指定N建筑物的数量。 (1 <= N <= 100000)。 第二条输入线将用于建筑物的高度。

    {h1,h2,h3,...,hn}
    

    第三行输入将给出成本数组

     {c1,c2,c3.....,cn}
    

    输出

    输出将只是所需的最低成本。

    示例输入:

    3
    
    2 1 3
    
    10 1000 1
    

    示例输出

    12
    

    说明:将所有建筑物的高度设为1,因此费用为 10 *(2-1)+ 1000 *(1-1)+ 1 *(3-1)即12。

    我知道蛮力方法是O(n ^ 2)。

    我认为的蛮力方法如下:

    无论常见高度是多少,都必须来自

     {h1,h2,h3,....,hn}
    

    即。 h必须等于h(i)中的任何一个。 现在检查每个h(i)我可以用O(n ^ 2)计算答案。

    可以更快地完成吗?

2 个答案:

答案 0 :(得分:2)

O(n log(n))解决方案

设h(i)表示第i个建筑物的高度,让c(i)表示第i个建筑物的成本。

  1. 步骤1:按照相应建筑物的高度按降序对建筑物进行分类。将这种布置称为P.即P(1)是最大建筑物的高度,P(n)是最小建筑物的高度。这需要O(n log n)。
  2. 步骤2:总结建筑物的所有高度。设S表示这个总和。此步骤需要O(n)时间。
  3. 步骤3:如果我们将高度低于第i个建筑物的所有建筑物的高度设置为等于SORTED ARRAY P中第i个建筑物的高度,即Cost_of_Increase(i),则表示Cost_of_Increase(i)表示成本。如果我们使建筑物P(i-1),P(i-2),...... P(n)等于P(i)建筑物的高度。
  4. 现在使用此递归:

    Cost_of_Increase(i)= Cost_of_Increase(i-1)+(h(i)-h(i-1))*(第(i-1)个建筑物到第P(n)个建筑物的成本总和)

    请注意,在上述递归中,i和i-1的顺序是根据P的顺序,即排序顺序。

    现在让Cost_of_decrease(i)表示如果我们使所有高度超过第i个建筑物的建筑物等于SORTED ARRAY P中第i个建筑物的高度,即Cost_of_decrease(i)如果我们建造建筑物P(1),P(2),... P(i-2),P(i-1)等于P(i)建筑物的高度。

    为此使用此递归:

    Cost_of_decrease(i)= Cost_of_decrease(i + 1)+(h(i + 1)-h(i))*(P(1)建筑物到P(i-1)建筑物的成本总和)

    因此,使所有建筑物的高度等于P(i)建筑物的总成本为:

    Cost_of_Increase(i)+ Cost_of_decrease(i)。

    一旦我们对所有建筑物都有这个,只需检查成本最小的那个,这就是答案。

    希望它有所帮助!

答案 1 :(得分:1)

在算法结束后,对所有建筑物的高度执行ternary search或使用hill climbing算法。对于每个高度,您可以计算线性时间的成本,因此总体复杂度将为O(N * log(H)),其中H是可能的最大结果高度。

编辑:这是一个适合你的伪代码片段(这是一种类似爬坡的方法)

  typedef long long ll;
  ll get_cost(int h) {
    if (h < 0 || h > MAX_HEIGHT) {
      return MAX_VAL; // some unreachable positive value
    }
    ...
  }


  int main() {
    ...
    int current = 0;
    int leftp, rightp;
    ll cv, lv, rv;
    ll step = SOME_BIG_ENOUGH_VALUE;
    while (step > 0) {
      leftp = current - step;
      rightp = current + step;
      cv = get_cost(current);
      lv = get_cost(leftp);
      rv = get_cost(rightp);
      if (cv <= rv && cv <= lv) {
        step /= 2;
      } else if (lv < rv) {
        current = leftp;
      } else {
        current = rightp;
      }
    }
    ...
  }