送货站选址问题

题目:有n个商店,分布在x[i]位置上,每个商店每天需要进货w[i]吨,问送货站建在哪里,代价最小?

分析:

进货量:w[0]  w[1]  w[2]  ...  w[i]   w[i+1]  w[i+2]  ...  w[n]

位   置:x[0]   x[1]   x[2]  ...  x[i]    x[i+1]   x[i+2]  ...  x[n]

送货站:                                    x^

假设送货站的位置在x处,如果x位于x[i]和x[i+1]之间,那么送货的代价是:

w[0]*(x - x[0]) + w[1]*(x - x[1]) +  ...  + w[i]*(x - x[i]) + w[i+1]*(x[i+1] - x) + w[i+2]*(x[i+2] -x) +  ...  w[n]*(x[n] - x) 化简为下面形式:

(w[i+1]*x[i+1] + w[i+2]*x[i+2] +  ...  + w[n]*x[n] - w[0]*x[0] - w[1]*x[1] -  ...  - w[i]*x[i]) + (w[0] + w[1] + ... + w[i] - w[i+1] - w[i+2] - ... - w[n])*x,x取值范围是x[i] 到 x[i+1]

如果(w[0] + w[1] + ... + w[i] - w[i+1] - w[i+2] - ... - w[n])为正值,x应该取x[i],反之,x应该取x[i+1],这样可以使得代价最小

从1到n-1遍历所有的i,分别计算两部分的值,将计算的代价值存储在一个数组中,扫描一遍数组,取出其中的最小代价值,就可以确定出x的位置。

在计算循环的过程中要反复计算 sum(w[0]x[0] ... w[i]x[i]) 和sum(w[i+1]x[i+1] ... w[n]x[n])这需要一层循环,再加上i本身的一层循环,算法的复杂度是O(n^2)的,其实sum的计算可以通过sum(w[0]x[0] ... w[i]x[i]) = sum(w[0]x[0] ... w[i-1]x[i-1]) + w[i]x[i]来计算,而sum(w[i+1]x[i+1] ... w[n]x[n]) = sum(w[0]x[0] ... w[n]x[n]) - sum(w[0]x[0] ... w[i]x[i])来计算,事先可以通过一次扫描计算出sum(w[i+1]x[i+1] ... w[n]x[n]),后面就不用再循环计算sum了,从而减少了一层循环,降低了复杂度到O(n)

预先计算和最后的求最小代价都是O(n),因此整个算法的复杂度为O(n)

程序如下:

#include <stdio.h>
#include <boost/scoped_ptr.hpp>
int DeliverySelection(int weight[], int position[], int length) {
  boost::scoped_ptr<int> cost_buffer(new int[length]);
  int* cost = cost_buffer.get();
  int sum_weight = 0;
  for (int i = 0; i < length; ++i) {
    sum_weight += weight[i];
  }
  int sum_cost = 0;
  for (int i = 0; i < length; ++i) {
    sum_cost += weight[i] * position[i];
  }
  int cost_ending_here = 0;
  int weight_ending_here = 0;
  int pos = 0;
  for (int i = 0; i < length; ++i) {
    cost_ending_here += weight[i] * position[i];
    weight_ending_here += weight[i];
    if (weight_ending_here - (sum_weight - weight_ending_here) > 0) {
      pos = position[i];
    } else {
      pos = position[i + 1];
    }
    cost[i] = (sum_cost - cost_ending_here) - cost_ending_here +
              (weight_ending_here - (sum_weight - weight_ending_here)) * pos;
  }
  int min_cost = 0x7FFFFFFF;
  int min_pos = -1;
  for (int i = 0; i < length; ++i) {
    if (cost[i] < min_cost) {
      min_cost = cost[i];
      min_pos = i;
    }
  }
  return position[min_pos];
}
    

int main(int argc, char** argv) {
  int weight[] = {2, 8, 5, 2, 3, 5, 6, 8, 1};
  int position[] = {0, 3, 7, 10, 11, 13, 15, 17,19};
  int array_size = sizeof(weight) / sizeof(int);
  int selected_position = DeliverySelection(weight, position, array_size);
  printf("DeliveryPosition:%d\n", selected_position);
}

相似问题:

编程之美 1.8

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值