POJ 1160 Post Office(抽象的二维DP)

题意:

有 n 个村庄,要求选定其中 p 个建立邮局,每个村庄使用离他最近的那个邮局,求一种方案使最终的距离总和最小;

(黑书 157 邮局)

思路:

1. 题目中有 2 个“最”:最近的邮局、距离总和最小 -> 对于第一个最我们可以采取预处理的方式 cost[i, j] 即 i, j 之间建立一个邮局的最近距离;

2. 最近的邮局这个很好解决:通过规律可以发现,如果邮局建在 i, j 的中间位置一定是最优的选择。下面解决距离总和最小;

3. dp[i, j] 代表 前 i 个邮局建立在前 j 个村庄的最小距离总和。相当于是这 i 个邮局各有一片管辖区域,如何划分使总距离最小:

4. 关于区间划分,这让人想到黑书上面任务调度类似的题目,推敲下有: dp[i, j] = min(dp[i, j], dp[i-1][k] + cost[k+1, j]);

 

#include <iostream>

#include <algorithm>

using namespace std;



const int MAXN = 310;

const int INFS = 0x3fffffff;



int dp[MAXN][MAXN], cost[MAXN][MAXN], x[MAXN];

int vill, office;



int calccost(int i, int j) {

    int ans = 0;

    while (i < j) {

        ans += x[j] - x[i];

        j--, i++;

    }

    return ans;

}



int workout() {

    for (int i = 0; i <= office; i++)

        for (int j = 0; j <= vill; j++)

            dp[i][j] = INFS;

    dp[0][0] = 0;



    for (int i = 1; i <= office; i++) {

        for (int j = i; j <= vill; j++) {

            for (int k = 0; k < j; k++)

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

        }

    }

    return dp[office][vill];

}



int main() {

    while (~scanf("%d%d", &vill, &office)) {

        x[0] = 0;

        for (int i = 1; i <= vill; i++)

            scanf("%d", &x[i]);



        for (int i = 1; i <= vill; i++)

            for (int j = i; j <= vill; j++)

                cost[i][j] = calccost(i, j);



        printf("%d\n", workout());

    }

    return 0;

}

你可能感兴趣的:(Office)