Description
Post offices will be built in some, but not necessarily all of the villages. A village and the post office in it have the same position. For building the post offices, their positions should be chosen so that the total sum of all distances between each village and its nearest post office is minimum.
You are to write a program which, given the positions of the villages and the number of post offices, computes the least possible sum of all distances between each village and its nearest post office.
Input
Output
Sample Input
10 5
1 2 3 6 7 9 11 22 44 50
Sample Output
9
思路:
1. dist[i][j] 表示在村子 i, j 之间选一点建邮局并使得 i,j 之间的所有村子到该邮局的距离之和最小. 选择方法是固定的, 总是选择 i,j 最中间的那个村子, mid = (i+j+1)/2
2. dp[i][j] 表示前 i 个村子建立 j 个邮局后各个村子到邮局的总距离之和的最小值
3. dp[i][j] = dp[k][j-1] + dist[k+1][i], 类似背包, 不过这里有个枚举的过程.
为什么第 k+1 个村庄非得去 (k+1,j) 之间的那个邮局, 这应该是个枚举的过程, 强制 0~j-1 分配 k 个, j~i 分配 1 个, 枚举所有可能性
总结:
1. 四边形不等式: 状态转移方程形如:f[i] = opt{f[j]+w[j , i]} 其中b[i] <= j <= i-1, 同时满足w[i , j] + w[i' , j'] <= w[i , j'] + w[i' , j], 其中 i <= i' <= j' <= j, 则能够使用四边形优化, 减少 k 的枚举量, 加速状态转移
代码:
#include <iostream>
using namespace std;
const int MAXN = 310;
int village[MAXN];
int dist[MAXN][MAXN];
int dp[MAXN][40];
int V, P, S; void preProcess() { for(int i = 1; i <= V; i ++) {
for(int j = i; j <= V; j ++) {
int mid = (i+j+1)>>1;
int sum = 0;
for(int k = i; k <= j; k ++) {
sum += abs(village[mid]-village[k]);
}
dist[i][j] = sum;
}
}
int INF = 0X3f;
memset(dp, INF, sizeof(dp));
dp[0][0] = 0; } // dp[i][j] = min(dp[k][j-1] + dist[k+1][j])
int mainFunc() {
for(int i = 1; i <= V; i ++) {
for(int j = 1; j <= P; j ++) {
for(int k = 0; k < i; k ++) {
dp[i][j] = min(dp[i][j], dp[k][j-1] + dist[k+1][i]);
}
}
} return dp[V][P];
}
int main() {
freopen("E:\\Copy\\ACM\\poj\\1160\\in.txt", "r", stdin);
while(cin>> V >> P) {
for(int i = 1; i <= V; i ++) {
scanf("%d", &village[i]);
}
preProcess(); cout << mainFunc() << endl;
}
return 0;
}