题目:http://poj.org/problem?id=1160
题意: 一些村庄被建立在一条笔直的高速公路边上,我们用一条坐标轴来描述这条高速公路,每一个村庄的坐标都是整数,没
有两个村庄坐标相同。两个村庄间的距离,定义为它们的坐标值差的绝对值。我们需要在一些村庄建立邮局——当然,并不是每
一个村庄都必须建立邮局,邮局必须被建立在村庄里,因此它的坐标和它所在的村庄坐标相同。每个村庄使用离它最近的那个
邮局,建立这些邮局的原则是:所有村庄到各自所使用的邮局的距离总和最小。
你的任务是编写一个程序,在给定了每个村庄坐标和将要建立的邮局数之后,按照上述原则,合理地选择这些邮局的位置。
求出的所有村庄到距离它最近的邮局的距离总和.
分析:给定一个序列,假设我们要建一个邮局,那么一定是在这个序列的中点,所以我们可以先预处理出序列区间[l,r]之间建立
一个邮局的最短距离和w[l][r],然后用dp[i][j]表示到i个村庄建立j个邮局的最短距离和,那么就有状态转移方程:
#include <iostream>
#include <string.h>
#include <stdio.h>
using namespace std;
const int INF = ~0U>>1;
const int N = 305;
int w[N][N];
int dp[N][35];
int a[N];
int n,m;
void Init(int a[],int n)
{
memset(w,0,sizeof(w));
for(int i=1;i<=n;i++)
for(int j=i+1;j<=n;j++)
w[i][j] = w[i][j-1] + a[j] - a[(i+j)>>1];
}
int Work()
{
for(int i=1;i<=n;i++)
{
dp[i][i] = 0;
dp[i][1] = w[1][i];
}
for(int j=2;j<=m;j++)
{
for(int i=j+1;i<=n;i++)
{
dp[i][j] = INF;
for(int k=j-1;k<i;k++)
dp[i][j] = min(dp[i][j],dp[k][j-1] + w[k+1][i]);
}
}
return dp[n][m];
}
int main()
{
while(~scanf("%d%d",&n,&m))
{
for(int i=1;i<=n;i++)
scanf("%d",&a[i]);
Init(a,n);
printf("%d\n",Work());
}
return 0;
}