1. 程式人生 > >題解【POJ1160】Post Office

題解【POJ1160】Post Office

nec order distance coo mini include sizeof input -i

【POJ1160】Post Office

Description

There is a straight highway with villages alongside the highway. The highway is represented as an integer axis, and the position of each village is identified with a single integer coordinate. There are no two villages in the same position. The distance between two positions is the absolute value of the difference of their integer coordinates.

Post offices will be built in some, but not necessarily all of the villages. A village and the post office in it have the same position. For building the post offices, their positions should be chosen so that the total sum of all distances between each village and its nearest post office is minimum.

You are to write a program which, given the positions of the villages and the number of post offices, computes the least possible sum of all distances between each village and its nearest post office.

Input

Your program is to read from standard input. The first line contains two integers: the first is the number of villages V, 1 <= V <= 300, and the second is the number of post offices P, 1 <= P <= 30, P <= V. The second line contains V integers in increasing order. These V integers are the positions of the villages. For each position X it holds that 1 <= X <= 10000.

Output

The first line contains one integer S, which is the sum of all distances between each village and its nearest post office.

Sample Input

10 5
1 2 3 6 7 9 11 22 44 50

Sample Output

9

Source

IOI 2000

Solution

簡化版題意:有N個村莊,每個村莊均有一個唯一的坐標,選擇P個村莊建郵局,問怎麽選擇,才能使每個村莊到其最近郵局的距離和最小,輸出這個最小值。

本題是一道區間DP題,比較復雜。

當我們在v個村莊中只建一個郵局,可以推導出,只有郵局位於中間位置,距離和才最小。

有一個特殊情況是,當村莊數為偶數,中間位置有兩個村莊,經過計算,兩個村莊的距離和相等,所以兩個位置均可。

可以聯想到,N個村莊建P個郵局,相當於每個郵局均有一個作用範圍,該郵局位於其作用範圍的中間位置,就是要找到一個k,使前k個村莊建P - 1個郵局,最後幾個村莊建一個郵局的方案滿足題意。

那麽,我們設:

dp[i][j]:前i個村莊建j個郵局的最小距離和

b[i][j]:第i個村莊到第j個村莊之間建1個郵局的最小距離和

因此,狀態轉移方程就是:

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

還有一點,計算b[i][j]時,b[i][j - 1]已經計算出來,而且可以推導出無論j為奇數還是偶數,b[i][j]均可以寫成b[i][j - 1] + j距離i、j中點的距離。

Code

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <algorithm>
#include <cmath>//頭文件

using namespace std;//使用標準名字空間

inline int gi()//快速讀入
{
    int f = 1, x = 0;
    char c = getchar();

    while (c < '0' || c > '9')
    {
        if (c == '-')
            f = -1;
        c = getchar();
    }

    while (c >= '0' && c <= '9')
    {
        x = x * 10 + c - '0';
        c = getchar();
    }

    return f * x;
}

int n, m, a[305], sum, b[305][305], dp[305][305];//m即為題中的p,sum為最終答案,b數組和dp數組的含義同Solution

int main()
{
    n = gi(), m = gi();
    
    for (int i = 1; i <= n; i++)
    {
        a[i] = gi();
    }
    //輸入
    memset(dp, 0x3f3f3f3f, sizeof(dp));//初始化dp數組為最大值
    
    for (int i = 1; i < n; i++)
    {
        for (int j = i + 1; j <= n; j++)
        {
            b[i][j] = b[i][j - 1] + a[j] - a[(i + j) >> 1];//b數組的初始化
        }
    }

    for (int i = 1; i <= n; i++)
    {
        dp[i][1] = b[1][i];//只建一個郵局的預處理
    }
    
    for (int i = 2; i <= m; i++)//要建i個郵局
    {
        for (int j = i; j <= n; j++)//1~j號村莊建i個郵局
        {
            for (int k = i - 1; k <= j - 1; k++)//1~k號村莊建i- 1個郵局
            {
                dp[j][i] = min(dp[j][i], dp[k][i - 1] + b[k + 1][j]);//DP主過程
            }
        }
    }
    
    sum = dp[n][m];//答案即為dp[n][m],就是在1~n號村莊中建m個郵局
    
    printf("%d", sum);//輸出最終答案
    
    return 0;//結束
}

題解【POJ1160】Post Office