POJ1160 【Post Office】
Description
There is a straight highway with villages alongside the highway. The highway is represented as an integer axis, and the position of each village is identified with a single integer coordinate. There are no two villages in the same position. The distance between two positions is the absolute value of the difference of their integer coordinates.
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
Your program is to read from standard input. The first line contains two integers: the first is the number of villages V, 1 <= V <= 300, and the second is the number of post offices P, 1 <= P <= 30, P <= V. The second line contains V integers in increasing order. These V integers are the positions of the villages. For each position X it holds that 1 <= X <= 10000.
Output
The first line contains one integer S, which is the sum of all distances between each village and its nearest post office.
Sample Input
10 5
1 2 3 6 7 9 11 22 44 50
Sample Output
9
Source
IOI 2000
Solution:
DP
状态:f[i][j]:前i个村庄,放j个邮局的最小sum值
输出:f[N][M]
转移方程:f[i][j]=min{f[k][j-1]+sum[k+1][i]}
解释一下:很显然前i个村庄的状态是由之前的状态转移而来的,但我们又不确定邮局的位置以及有无,就需要枚举前k个村庄的状态(其中1<=k<=i),并且前k个村庄一定有j-1个邮局,再加上从k+1~i中建一个邮局的最小sum值
sum[i][j]:表示从i->j中建一个邮局的最小sum值。
如果i->j中只有一个邮局而无别的村庄很显然最小值为pos[j]-pos[i];类比而来如果中间存在两个村庄,我们就要在这两个村庄中建造,这样无限的推理下去,最后会到一个标记中间值建造邮局。
sum[i][j]=sum[i][j-1]+pos[j]-pos[(i+j)/2];
注意:
- f[i][1]=sum[1][i];
- 每次f[i]][j]的初值要附成INF
- j在i前枚举,且j>=2
Code:
#include <stdio.h>
#include <string.h>
#define MAXN 500
#define INF 999999
int n,m;
int a[MAXN],sum[MAXN][MAXN],f[MAXN][MAXN];
int min(int a,int b){return a<b?a:b;}
int main()
{
scanf("%d %d",&n,&m);
for(int i=1;i<=n;i++)
{
scanf("%d",&a[i]);
}
for(int i=1;i<n;i++)
{
for(int j=i+1;j<=n;j++)
{
sum[i][j]=sum[i][j-1]+a[j]-a[(i+j)/2];
}
}
for(int i=1;i<=n;i++)
{
f[i][1]=sum[1][i];
}
for(int j=2;j<=m;j++)
{
for(int i=j+1;i<=n;i++)
{
f[i][j]=INF;
for(int k=1;k<i;k++)
{
f[i][j]=min(f[i][j],f[k][j-1]+sum[k+1][i]);
}
}
}
printf("%d\n",f[n][m]);
return 0;
}