邮局--dp经典问题

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



你可能感兴趣的:(邮局--dp经典问题)