简体   繁体   中英

How to find the minimum cost?

I'm trying to solve a problem which consists of finding minimum cost.The problem can be stated as: Given n buildings and for each building its height and cost is given.Now task is to find minimum cost so that all the buildings become equal to same height.Each building can be considered as a vertical pile of bricks where each brick can be added or removed with the cost associated with that building.

For example: Say there are n=3 buildings with heights of 1,2,3 and cost 10,100,1000 respectively.

Here, minimum cost will be equal to 120.

Here is the link to the problem:

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

An obvious answer will be to find the cost associated with each of the heights for all the buildings and then give as output the minimum cost from them.This is O(n^2).

In search for a better solution I tried finding the height with minimum value of ratio of height/cost.Then all the buildings must be equal to this height and calculate the cost and give as output.But this is giving me wrong answer. Here is my implementation:

Based on the below answers I have updated my code using weighted average but still not working.It's giving me wrong answer.

#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;
}

Any idea how to solve this ?

Try thinking about heights as values and costs as certainty,significance.

Simple weighted average should do the trick here:

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

optimalheight = round(double(weightedsum)/costsum);

Then count the cost knowing the optimal height:

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

I recently encountered a similar question, the minor difference is that in my question, it's only possible to add floors to a building, you cannot remove it. But the idea should be similar. Feel free to drop me any comments or questions.

I think one good way to approach this question is: Sort the input first, this could usually be done with language built-in API calls, in Java, I used Arrays.sort(). This is usually nLog(n) time complexity. After sorting, we can maintain a window of size m, inside the window, we could compute the minimum cost for each window, while we shift the window from the beginning to the end, we compute and update a global minimum cost. Here's the implementation:

    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;
    }

Also I shared my solution here: Space Rock question

Here is a solution that requires the building heights be sorted (I'm going to assume from shortest to tallest). If the data is already sorted then this should run in O(N) time.

Let k be the height of all the buildings, so we want to find the optimal k. The cost of adjusting all these buildings is given by:

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

Now because they are sorted we can find an index i such that for all j <= i, hj <= k and for all j > i, hj > k. This means we can rewrite our cost equation to be:

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

Now we will iterate through the k values between the shortest and the tallest building until we find the one with the lowest cost (we will see further down that we don't have to check every single one) Calculating the cost at every iteration is N operations, so we will find a recursive definition of our cost function instead:

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

We can move the '1' terms out of the sums to get:

    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).

Now p is the new i, and there are 2 possible cases: p = i or p = i+1. if p = i:

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

and if 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).

In the case where p=i we can actually find M(k+m) directly from M(k) because at each iteration we are only adding a constant term (constant in terms of k that is) so if p = i:

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

This means that our function forms a straight line between iterations where i is constant. Since we are interested in when our function goes from decreasing to increasing this cannot happen between in the middle of all these iterations. It can only happen when i increments (p = i+1) or the first step after (since the line is different from the line leading up to it). From what's here so far the algorithm would go something like:

  1. Sort the heights if necessary (O(NlogN))
  2. Initialize your 4 sums (the two sums in M(k) and the two additional sums introduced in M(k+1)) (O(N))
  3. iterate through your heights like this (O(N)) finding the minimum value as you go:

    -Increase k to the height of the next tallest building less one (using the M(k+m)) and see if this represents a new minimum

    -Increase k by one changing i values and see if this represents a new minimum

  4. Print out answer.

There are some other optimizations possible here that I haven't thought too much about yet. The obvious one is to not recalculate your sums whenever i changes.

I apologize if the math is hard to read, I'm new at StackOverflow and haven't figured out all the formats possible.

I don't have any code to support this so I hope this is good enough.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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