题目: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; }