12个工厂分布在一条东西向高速公路的两侧,工厂距离公路最西端的距离分别是0、4、5、10、12、18、27、30、31、38、39、47.在这12个工厂中选取3个原料供应厂,使得剩余工厂到最近的原料供应厂距离之和最短,问应该选哪三个厂?
分析:
1、是一维问题,不是二维,可以抽象成:有12个点分布在一维坐标轴上,选择3个点,使得剩余的点到最近的点的距离之和最小。
2、工厂距离是从小到大排序的。
3、从N个工厂中选择1个原料厂,选择位于中位数位置的工厂,距离之和最短。
4、设A[i][j]表示从前i个工厂选择j个原料厂的最短距离,B[i][j]表示从第i个工厂到第j个工厂选择1个原料厂的最短距离。
对B[i][j]而言,1<=i<=j<=N
对A[i][j]而言,1<=j<=i<=N
从前i个工厂选择j个原料厂,可分为两部分:从前k个工厂选择j-1个原料厂和从第k+1个工厂到第i个工厂选择1个原料厂
i, j, k满足的条件为:1<=j-1<=k<i, k+1<=i
即,2<=j<=i, j-1<=k<=i
为什么j-1要大于等于1呢?若j-1等于0, 则前k个工厂没有原料厂了。
所以,递归解为:
A[i][j] = B[1][i], 即j=1时
A[i][j] = min{ A[k][j-1] + B[k+1][i] },其中2<=j<=i, j-1<=k<=i
源程序:
// 12个工厂分布在一条东西向高速公路的两侧,工厂距离公路最西端的距离分别是0、4、5、10、12、18、27、30、 31、38、39、47.
// 在这12个工厂中选取3个原料供应厂,使得剩余工厂到最近的原料供应厂距离之和最短,问应该选哪三个厂?
// 参数:
// array: 工厂距离数组,array[1...n]为有效值,array[0]置0
// length: 有效元素数目
// 求从第begin个工厂到第end个工厂设1个原料厂的最短距离
// 1<=begin<=end<=n
static int min_distance(int *array, int begin, int end)
{
int mid = begin + (end - begin) / 2;
int distance = 0;
for (int i = begin; i <= end; ++i)
{
distance += abs(array[i]-array[mid]);
}
return distance;
}
// 输出从前i个工厂选择的j个原料厂
static void print_selected_factory(const multi_array<int, 2> &opt, int length, int i, int j)
{
if (i <= j)
{
for (int k = 1; k <= i; ++k)
{
cout << k << " ";
}
return;
}
int k = opt[i][j];
print_selected_factory(opt, length, k, j-1);
cout << k+1 + (i-k-1)/2 << " ";
}
int min_sum_of_distance(int *array, int length, int number)
{
if (array == NULL || length < 1)
return 0;
// min_distance_1[i][j]表示从第i个工厂到第j个工厂设1个原料厂的最短距离
multi_array<int, 2> min_distance_1(extents[length+1][length+1]);
for (int i = 0; i <= length; ++i)
min_distance_1[i][0] = 0;
for (int j = 1; j <= length; ++j)
min_distance_1[0][j] = 0;
for (int i = 1; i <= length; ++i)
for (int j = i; j <= length; ++j)
min_distance_1[i][j] = min_distance(array, i, j);
// min_distance_m[i][j]表示从前i个工厂中设j个原料厂的最短距离之和
multi_array<int, 2> min_distance_m(extents[length+1][length+1]);
multi_array<int, 2> opt(extents[length+1][length+1]);
for (int i = 0; i <= length; ++i)
min_distance_m[i][0] = 0;
for (int j = 1; j <= length; ++j)
min_distance_m[0][j] = 0;
for (int i = 1; i <= length; ++i)
{
int j = 1;
min_distance_m[i][j] = min_distance_1[1][i];
for (j = 2; j <= i; ++j)
{
min_distance_m[i][j] = INT_MAX;
for (int k = max(1, j-1); k < i; ++k)
{
int tmp = min_distance_m[k][j-1] + min_distance_1[k+1][i];
if (tmp < min_distance_m[i][j])
{
min_distance_m[i][j] = tmp;
opt[i][j] = k;
}
}
}
}
cout << "min distance: " << min_distance_m[length][number] << endl;
print_selected_factory(opt, length, length, number);
cout << endl;
return min_distance_m[length][number];
}
int main(int argc, char **argv)
{
int array[] = {0, 0, 4, 5, 10, 12, 18, 27, 30, 31, 38, 39, 47};
int length = sizeof(array) / sizeof(int);
min_sum_of_distance(array, length-1, 3);
return 0;
}
参考:
http://blog.youkuaiyun.com/julianxiong/article/details/7381214