区间DP POJ1160村庄邮局问题

POJ1160

题目大意:一系列村庄在一维坐标系上有序的排列,建设p个邮局,问各个村庄到邮局的最短距离和。

线性区间DP问题

dp数组的值为最短/最优距离

村庄和邮局为限制

dp[i][j]表示前i个村庄有j个邮局的最优解

分析最小子问题可得前i个村庄有1个邮局的最优解——中间的村庄

所以分解区间dp[i][j] = min(dp[i][j],dp[k][j-1] + sum[k+1][i])

sum[i][j]数组表示从i到j村庄放一个邮局的最优解

j,i,k的遍历,最终得到最优解

外层遍历的是邮局的个数,这样才能遍历村庄的个数(我们所未知的情况是村庄的个数大于邮局的个数)

对了sum【i】【j】和sum[i][j-1]存在某种关系呦,一推就出来了~~

#include <iostream>
#include <cstdio>
#include <string.h>
#define inf (1e8 + 9e7)
using namespace std;
const int maxn = 1e3 + 1e2;
int dp[maxn][maxn];
int sum[maxn][maxn];
int pos[maxn];
void init()
{
    memset(sum,0,sizeof(sum));
}
int main()
{
    int n,pn;
    while(~scanf("%d%d",&n,&pn))
    {
        init();
        for(int i = 1;i <= n;i++)
            scanf("%d",&pos[i]);

        for(int i = 1;i <= n;i++)
        {
            for(int j = i+1;j <= n;j++)
            {
                sum[i][j] = sum[i][j-1] + pos[j] - pos[(i + j)/2];
            }
            dp[i][i] = 0;
        }

        for(int i = 1;i <= n;i++)
        {
            dp[i][1] = sum[1][i];
        }

        for(int j = 2;j <= pn;j++)//建造一个的情况已经铺垫好了
            for(int i = j+1;i <= n;i++)//村庄首先必须保证得比
            {
                //接下来我要做的是遍历k来找到到底几个村庄放j-1个最优
                dp[i][j] = inf;
                for(int k = j - 1;k < i;k++)
                {
                    dp[i][j] = min(dp[i][j],dp[k][j-1] + sum[k+1][i]);
                }
            }
        printf("%d
",dp[n][pn]);
    }
    return 0;
}
原文地址:https://www.cnblogs.com/DF-yimeng/p/9354117.html