邮局--dp经典问题

来源:互联网 发布:edg淘宝官方旗舰店衣服 编辑:程序博客网 时间:2024/04/29 17:27

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