POJ1160 P个邮局N个村庄求最短总距离

有意思的一道题,N个一维坐标点上的村庄中选择P个村庄建邮局,要使总距离最短。用DP方法做, 在第0个村庄(升序)到第i个村庄建立j个邮局的最少总距离,是在第0个到第i个任取第j个点,第0个到第k个之间建立j-1个邮局的最少总距离加上在第(k+1)个到第i个村庄建立一个邮局的总距离之和的最小值(用形式化语言描述更清晰)。
第i个村庄到第j个村庄建立1个邮局的最小总距离是容易求的。这个邮局应建在(i+j)/2处。假定中点只有一个,即j-i为偶数,不论邮局建在何处,关于中心点对称的两个村庄到邮局的总距离最短是邮局建在中间那点此时总距离是两个村庄的距离和,把这些值累加仍然是最小,只需满足邮局在中点。j-i为奇数也是一样的。另外在两个关于中心点对称的位置建邮局距离和是一样的。代码中计算sin[i][j]时用了简单的计算方法,就是这个道理。

#include <cstdio> #include <limits.h> #include <algorithm> using namespace std; int v, p; int vilgs[300]; int sin[300][300]; int cost[300][30]; int main() { long i, j, k; //输入 scanf("%d%d", &v, &p); for (i = 0; i < v; ++i) { scanf("%d", &vilgs[i]); } //计算sin数组 for (i = 0; i < v; ++i) { for (j = i + 1; j < v; ++j) { #if 0 for (k = i; k <= j; ++k) { sin[i][j] += abs(vilgs[k] - vilgs[(i + j) / 2]); } #else //优化:注意,这里简化了计算,利用了对称位置点对所有点求和和不变的性质,无论(i,j-1)有奇数个点或偶数个变成(i,j)之后最佳位置不变或到对称的最佳位置 sin[i][j] = sin[i][j - 1] + vilgs[j] - vilgs[(i + j) / 2]; #endif } } for (i = 0; i < v; ++i) { cost[i][0] = sin[0][i]; } for (k = 1; k < p; ++k) for (i = k + 1; i < v; ++i) { for (cost[i][k] = INT_MAX, j = k - 1; j < i; ++j) { cost[i][k] = min(cost[i][k], cost[j][k - 1] + sin[j + 1][i]); } } printf("%d/n", cost[v - 1][p - 1]); return 0; }

你可能感兴趣的:(POJ1160 P个邮局N个村庄求最短总距离)