【问题标题】:How to find the minimum cost?如何找到最低成本?
【发布时间】:2012-04-05 04:26:57
【问题描述】:

我正在尝试解决一个包括找到最低成本的问题。这个问题可以表述为:给定 n 个建筑物,并且给定每栋建筑物的高度和成本。现在的任务是找到最低成本,以便所有建筑物的高度相同。每座建筑物都可以被视为垂直的砖堆,其中每块砖都可以通过与该建筑物相关的成本来添加或移除。

例如: 假设有 n=3 栋建筑物,高度分别为 1,2,3,成本分别为 10,100,1000。

在这里,最低成本将等于 120。

这里是问题的链接:

http://www.spoj.pl/problems/KOPC12A/

一个明显的答案是找出与所有建筑物的每个高度相关的成本,然后将它们的最低成本作为输出。这是 O(n^2)。

为了寻找更好的解决方案,我尝试找到高度/成本比率最小值的高度。然后所有建筑物必须等于这个高度并计算成本并作为输出给出。但这给了我错误的答案. 这是我的实现:

根据以下答案,我已使用加权平均值更新了我的代码,但仍然无法正常工作。它给了我错误的答案。

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<algorithm>

using namespace std;

long long fun(int h[],int c[],int optimal_h,int n){
    long long res=0;
    for(int i=0;i<n;i++){
        res += (abs(h[i]-optimal_h))*c[i];
    }   
    return res;
}

int main()
{
    int t;
    cin>>t;
    for(int w=0;w<t;w++){
        int n;
        cin>>n;
        int h[n];
        int c[n];
        int a[n];
        int hh[n];
        for(int i=0;i<n;i++){
            cin>>h[i];
            hh[i]=h[i]; 
        }
        sort(hh,hh+n);
        for(int i=0;i<n;i++)
            cin>>c[i];

        long long w_sum=0;  
        long long cost=0;

        for(int i=0;i<n;i++){
            w_sum += h[i]*c[i];
            cost += c[i];   
        }

        int optimal_h;
        if(cost!=0){
            optimal_h=(int)((double)w_sum/cost + 0.5);
            if(!binary_search(hh,hh+n,optimal_h)){
                int idx=lower_bound(hh,hh+n,optimal_h)-hh;
                int optimal_h1=hh[idx];
                int optimal_h2=hh[idx-1];
                long long res1=fun(h,c,optimal_h1,n);
                long long res2=fun(h,c,optimal_h2,n);
                if(res1<res2)
                    cout<<res1<<"\n";   
                else
                    cout<<res2<<"\n";
            }
            else{
                long long res=fun(h,c,optimal_h,n);
                cout<<res<<"\n";
            }

        }
        else
            cout<<"0\n";
    }

    return 0;
}

知道如何解决这个问题吗?

【问题讨论】:

  • 如果您使用的是c++,请不要将其标记为c
  • 和@dark_shadow,请不要为您的代码链接到外部站点。只需将其放在这里并正确格式化即可。
  • 一个小技巧,不知道有没有用;计算建筑物高度之间的加权平均值,其中权重是成本。
  • 旁白:C++没有变长数组,避免int h[n];;更喜欢std::vector&lt;int&gt; h(n);
  • 这个问题可能跑题了。您的任务可以描述为 LAD 问题:最小化sum(abs(h[i] - x) * c[i])。见en.wikipedia.org/wiki/Least_absolute_deviations

标签: c++ algorithm linear-algebra


【解决方案1】:

我最近遇到了一个类似的问题,细微的区别是在我的问题中,只能将楼层添加到建筑物中,而不能删除它。但想法应该是相似的。如有任何问题或问题,请随时给我。

我认为解决这个问题的一种好方法是: 首先对输入进行排序,这通常可以通过语言内置的 API 调用来完成,在 Java 中,我使用了 Arrays.sort()。这通常是 nLog(n) 时间复杂度。 排序后,我们可以维护一个大小为 m 的窗口,在窗口内,我们可以计算每个窗口的最小成本,同时我们将窗口从开始移动到结束,我们计算并更新全局最小成本。 这是实现:

    static long minFloors(long[] buildings, int m) {
        //sort buildings
        Arrays.sort(buildings);
        //maintain a window of size m, compute the minCost of each window, update minCost along the way as the final result
        long minCost = Long.MAX_VALUE;
        for(int i = 0; i <= buildings.length-m; i++){
            long heightToMatch = buildings[i+m-1];
            if(heightToMatch == buildings[i]) return 0;//if the last building's height equals the first one, that means the whole window if of the same size, we can directly return 0
            long thisCost = 0; 
            for(int j = i+m-1; j >= i; j--){
                thisCost += heightToMatch - buildings[j];
            }
            minCost = Math.min(minCost, thisCost);
        }
        return minCost;
    }

我也在这里分享了我的解决方案: Space Rock question

【讨论】:

    【解决方案2】:

    这是一个需要对建筑物高度进行排序的解决方案(我将假设从最低到最高)。如果数据已经排序,那么这应该在 O(N) 时间内运行。

    设k是所有建筑物的高度,所以我们要找到最优的k。 调整所有这些建筑物的成本如下:

        M = Sum(|k-hj|cj, j from 0 to N).
    

    现在因为它们已排序,我们可以找到一个索引 i,使得对于所有 j i,hj > k。 这意味着我们可以将成本方程改写为:

        M = Sum((k-hj)cj, j = 0 to i) + Sum((hj-k)cj, j = i+1 to N).
    

    现在我们将遍历最短和最高建筑物之间的 k 个值,直到找到成本最低的建筑物(我们将进一步看到,我们不必检查每一栋建筑物) 每次迭代计算成本是 N 次操作,因此我们将找到成本函数的递归定义:

        M(k+1) = Sum((k+1-hj)cj, j = 0 to p) + Sum((hj-k-1)cj, j = p+1 to N).
    

    我们可以将“1”项移出总和得到:

        M(k+1) = Sum((k-hj)cj, j = 0 to p) + Sum((hj-k)cj, j = p+1 to N) + Sum(cj, j = 0 to p) - Sum(cj, j = p+1 to N).
    

    现在 p 是新的 i,有两种可能的情况:p = i 或 p = i+1。 如果 p = i:

        M(k+1) = M(k) + Sum(cj, j = 0 to p) - Sum(cj, j = p+1 to N)
    

    如果 p = i+1

        M(k+1) = M(k) + Sum(cj, j = 0 to p) - Sum(cj, j = p+1 to N) + 2(k+1 - h(i+1))c(i+1).
    

    在 p=i 的情况下,我们实际上可以直接从 M(k) 中找到 M(k+m),因为在每次迭代中我们只添加一个常数项(即 k 的常数)所以如果 p =我:

        M(k+m) = M(k) + m(Sum(cj, j = 0 to p) - Sum(cj, j = p+1 to N)).
    

    这意味着我们的函数在 i 为常数的迭代之间形成一条直线。因为我们感兴趣的是我们的函数何时从减少变为增加,所以这不可能发生在所有这些迭代的中间。它只能在 i 递增 (p = i+1) 或之后的第一步(因为该行与通往它的行不同)时发生。 从目前的情况来看,算法将类似于:

    1. 必要时对高度进行排序 (O(NlogN))
    2. 初始化您的 4 个总和(M(k) 中的两个总和以及 M(k+1) 中引入的两个额外总和)(O(N))
    3. 像这样迭代你的高度 (O(N)) 找到最小值:

      -将k增加到下一个最高建筑物的高度减一(使用M(k+m)),看看这是否代表一个新的最小值

      -将 k 增加一改变 i 值,看看这是否代表一个新的最小值

    4. 打印出答案。

    这里还有一些其他可能的优化,我还没有考虑太多。 显而易见的是,当 i 发生变化时不要重新计算总和。

    如果数学难以阅读,我深表歉意,我是 StackOverflow 的新手,还没有弄清楚所有可能的格式。

    我没有任何代码来支持这一点,所以我希望这已经足够好了。

    【讨论】:

      【解决方案3】:

      尝试将高度视为价值,将成本视为确定性、意义。

      简单的加权平均应该可以解决问题:

      costsum=0;
      weightedsum=0;
      for(int i=0; i<n; ++i)
      {
         costsum += c[i];
         weightedsum += h[i]*c[i];
      }
      
      optimalheight = round(double(weightedsum)/costsum);
      

      然后在知道最佳高度的情况下计算成本:

      cost=0;
      for(int i=0; i<n; ++i)
         cost += c[i] * abs(h[i] - optimalheight);
      

      【讨论】:

      • 我在您链接的问题描述中找不到任何声明“高度应该是数组中存在的某个值”。
      • Stanwise 编写了伪代码,您必须声明 costsum、cost 和 weightedsum 的类型,并为 round 和 abs 函数包含
      • 如果你想知道背后的逻辑。然后制定一个成本函数并区分 w.r.t 到最佳高度以获得所需的高度。这是基础数学
      • -1。这是错误的。考虑问题中的示例:costsum = 1110, weightedsum=3210,它给出的最佳高度为 2.89。正确的最佳高度是 1000
      猜你喜欢
      • 2021-09-06
      • 1970-01-01
      • 2016-12-05
      • 2014-08-31
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-03-29
      • 1970-01-01
      相关资源
      最近更新 更多