求把p个邮局建在v个村庄对应的最小距离
感觉这个题挺复杂的,一开始之想到用二维数组来dp
后来看了题解才知道自己想错了
求解dp的过程中肯定要依赖于当前的最小距离
所以还需要计算一个数组来存储i-j村庄间建一个邮局所需的最小距离
而因为给出的位置是递增的
所以一段区间我们取中位数可以保证在这里建设邮局到达所有村庄距离最小
而状态转移方程是:
dp[i][j]代表把在前j个村庄建设j个邮局所对应的最小距离(i>=j)
dp[i][j] = min(dp[k][j-1]+cost[k+1][j])//(j-1 <= k <= i-1)
代码如下:
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
int a[310];
int cost[310][310];
int dp[310][32];
void get_cost(int v) {
int i, j, k, m;
memset(cost, 0, sizeof(cost));
for(i=1; i<=v; ++i) {
for(j=i; j<=v; ++j) {
cost[i][j] = 0;
m = (i+j) >> 1;
for(k=i; k<=j; ++k) {
cost[i][j] += (a[m]-a[k]) >= 0 ? a[m]-a[k] : a[k]-a[m];
}
}
}
}
int main(void) {
int p, v;
while(scanf("%d%d", &v, &p) != EOF) {
for(int i=1; i<=v; ++i) {
scanf("%d", &a[i]);
}
//dp[i][j] = min(dp[i-1][k]+cost[k+1][j]);
get_cost(v);
for(int i=1; i<=v; ++i) {
dp[i][i] = 0;
dp[i][1] = cost[1][i];
}
for(int j=2; j<=p; ++j)
for(int i=j+1; i<=v; ++i) {
dp[i][j] = 999999;
for(int k=j-1; k<i; ++k) {
dp[i][j] = min(dp[i][j], dp[k][j-1]+cost[k+1][i]);
// printf("dp[%d][%d] = %d\n", i, j, dp[i][j]);
}
}
printf("%d\n", dp[v][p]);
}
return 0;
}