POJ 1160 Post Office(抽象的二维DP)
题意:
有 n 个村庄,要求选定其中 p 个建立邮局,每个村庄使用离他最近的那个邮局,求一种方案使最终的距离总和最小;
(黑书 157 邮局)
思路:
1. 题目中有 2 个“最”:最近的邮局、距离总和最小 -> 对于第一个最我们可以采取预处理的方式 cost[i, j] 即 i, j 之间建立一个邮局的最近距离;
2. 最近的邮局这个很好解决:通过规律可以发现,如果邮局建在 i, j 的中间位置一定是最优的选择。下面解决距离总和最小;
3. dp[i, j] 代表 前 i 个邮局建立在前 j 个村庄的最小距离总和。相当于是这 i 个邮局各有一片管辖区域,如何划分使总距离最小:
4. 关于区间划分,这让人想到黑书上面任务调度类似的题目,推敲下有: dp[i, j] = min(dp[i, j], dp[i-1][k] + cost[k+1, j]);
#include <iostream>
#include <algorithm>
using namespace std;
const int MAXN = 310;
const int INFS = 0x3fffffff;
int dp[MAXN][MAXN], cost[MAXN][MAXN], x[MAXN];
int vill, office;
int calccost(int i, int j) {
int ans = 0;
while (i < j) {
ans += x[j] - x[i];
j--, i++;
}
return ans;
}
int workout() {
for (int i = 0; i <= office; i++)
for (int j = 0; j <= vill; j++)
dp[i][j] = INFS;
dp[0][0] = 0;
for (int i = 1; i <= office; i++) {
for (int j = i; j <= vill; j++) {
for (int k = 0; k < j; k++)
dp[i][j] = min(dp[i][j], dp[i-1][k] + cost[k+1][j]);
}
}
return dp[office][vill];
}
int main() {
while (~scanf("%d%d", &vill, &office)) {
x[0] = 0;
for (int i = 1; i <= vill; i++)
scanf("%d", &x[i]);
for (int i = 1; i <= vill; i++)
for (int j = i; j <= vill; j++)
cost[i][j] = calccost(i, j);
printf("%d\n", workout());
}
return 0;
}
-------------------------------------------------------
kedebug
Department of Computer Science and Engineering,
Shanghai Jiao Tong University
E-mail: kedebug0@gmail.com
GitHub: http://github.com/kedebug
-------------------------------------------------------