邮局问题

来源:互联网 发布:淘宝上海华硕商城 编辑:程序博客网 时间:2024/04/29 01:55

题意:有横向排列的P个村庄,每个村庄都有一个坐标位置。在这P个村庄上要建V个邮局。问这P个村庄中建造V个邮局之后,所有村庄到最近的邮局的距离的最小值是多少?

解答:dp[i][j]表示前i个村庄建造j个邮局的最小距离之和。

dp[i][j] = min(dp[i][j],dp[k][j-1] + w[k+1][j])

w[k+1][j]表示从第k+1个村庄到第j个村庄建立一个邮局的最小距离之和。

在两个村庄之间建立一个邮局的最小距离之和:这一个邮局应当放在中间的村庄。

那么,首先我们要预处理w数组。它又有一个状态转移方程:w[i][j] = w[i][j-1] + x[j] - x[(int)((i+j)/2)]

接下来,我们进行dp.初始化:从第二个村庄到第P个村庄建立一个村庄的值。

dp:外层循环:建的邮局数(j)(哪个放外层循环可由状态转移方程推断)

#include<iostream>#include<cstdio>#include<cstring>#include<algorithm>#include<cmath>using namespace std;const int INF = 1 << 30;const int MAXN = 300 + 10;int dp[MAXN][40];int x[MAXN];int w[MAXN][MAXN];int s[MAXN][MAXN];int main(){    int P,V;    while(~scanf("%d%d",&P,&V))    {        for(int i = 1;i <= P;i++)            scanf("%d",&x[i]);        sort(x+1,x+1+P);        memset(w,0,sizeof(w));        memset(s,0,sizeof(s));        for(int i = 1;i <= P;i++)            for(int j = 1;j <= V;j++)                dp[i][j] = INF;        for(int i = 1;i <= P;i++)        {            dp[i][0] = 0;        }        for(int i = 1;i < P;i++)            for(int j = i+1;j <= P;j++)                w[i][j] = w[i][j-1] + x[j] - x[(int)((i+j)/2)];        for(int i = 2;i <= P;i++)            dp[i][1] = w[1][i];        for(int j = 2;j <= V;j++)   //½¨j¸ö´åׯ            for(int i = j+1;i <= P;i++)            {                for(int k = s[i-1][j];k <= s[i][j-1];k++)                {                    dp[i][j] = min(dp[i][j],dp[k][j-1] + w[k+1][i]);                    if(dp[i][j] == dp[k][j-1] + w[k+1][i])                        s[i][j] = k;                }            }        printf("%d\n",dp[P][V]);    }    return 0;}




原创粉丝点击