zoukankan      html  css  js  c++  java
  • POJ 1485:Fast Food(dp)&& 面试题

    题目链接

    题意

    给出 n 个餐厅,m 个停车场,现在要将 n 个餐厅中的 m 个变成停车场,使得每个餐厅到最近的停车场的距离之和最短,输出哪个餐厅变成停车场和它服务哪些餐厅,还有最短距离之和。

    思路

    首先确定在 i 到 j 之间,一定是选择 i 和 j 的中位数那个餐厅作为停车场可以使得i到j的餐厅到停车场的距离最短。

    接下来定义状态 dp[i][j] 为前 i 个餐厅中有 j 个改装为停车场的最短距离之和。

    设想如果前 j - 1 个停车场服务着前 k-1 个餐厅,那么剩下的最后一个停车场(第 j 个)就要服务 [k, i] 的餐厅了。

    所以得到递推式:dp[i][j] = min(dp[i][j], dp[k-1][j-1] + 第k个餐厅到第i个餐厅的花费)。

    这个花费可以预处理出来,定义 cost[i][j] 为 [i, j] 中修建一个停车场,其他 [i, j] 中的餐厅到这个停车场的距离之和。

    还有一个难点就是输出路径的时候,用三个数组表示 dp[i][j] 的时候,最后一个停车场的位置,服务的餐厅的起点,服务的餐厅的终点,然后用 dfs 回溯的时候输出。

    #include <cstdio>
    #include <cstring>
    #include <cstdlib>
    using namespace std;
    const int N = 211;
    const int INF = 0x3f3f3f3f;
    int n, m, x[N], dp[N][N], cost[N][N];
    int st[N][N], ed[N][N], id[N][N];
    
    void dfs(int i, int j) {
        if (i < 1 || j < 1) return ;
        dfs(st[i][j]-1, j-1);
        printf("Depot %d at restaurant %d serves ", j, id[i][j]);
        if (st[i][j] == ed[i][j]) printf("restaurant %d
    ", st[i][j]);
        else printf("restaurants %d to %d
    ", st[i][j], ed[i][j]);
    }
    
    int main() {
        int t = 0;
        while (scanf("%d%d", &n, &m) && n && m) {
            for (int i = 1; i <= n; i++) scanf("%d", &x[i]);
            for (int i = 1; i <= n; i++) {
                for (int j = i; j <= n; j++) {
                    cost[i][j] = 0;
                    for (int k = i; k <= j; k++)
                        cost[i][j] += abs(x[k] - x[(i+j)/2]);
                }
            }
            memset(dp, INF, sizeof dp);
            dp[0][0] = 0;
            for (int i = 1; i <= n; i++) { // 枚举当前要放多少个包裹
                for (int j = 1; j <= i && j <= m; j++) { // 枚举仓库,要求仓库的数量比包裹数量少
                    for (int k = j; k <= i; k++) {
                        // 枚举从第k个包裹到第i个包裹全都放到最后一个仓库,
                        // 而且满足前面的j-1个仓库都至少一个包裹
                        int now = dp[k-1][j-1] + cost[k][i];
                        if (dp[i][j] > now) {
                            dp[i][j] = now;
                            st[i][j] = k; ed[i][j] = i; // st,ed 分别记录最后一个仓库的起点和终点
                            id[i][j] = (k + i) / 2; // id 记录的是位置
                        }
                    }
                }
            }
            printf("Chain %d
    ", ++t);
            dfs(n, m);
            printf("Total distance sum = %d
    
    ", dp[n][m]);
        }
        return 0;
    }
    
    /*
    6 3
    1 3 7 9 10 16
    5 3
    1 3 7 9 10
    1 1
    5
    */
    

    在面试的时候被问到如果那个花费是距离的平方的时候,什么时候最优。
    自己当场在平均值和中位数两者间试,试了一下还是被提示了,然后让我推,也推得不好。
    然后就引申出了这个问题。然后当场不会做,因此在这里补一下。

    具体的题目是:有 n 个 packages,m 个仓库,要让这些 packages 到最近的仓库的距离的平方之和最短,问最小的距离和。

    #include <bits/stdc++.h>
    using namespace std;
    const int N = 211;
    const int INF = 0x3f3f3f3f;
    int n, m, x[N];
    double dp[N][N], cost[N][N];
    
    int main() {
        scanf("%d%d", &n, &m);
        for (int i = 1; i <= n; i++) scanf("%d", &x[i]);
        for (int i = 1; i <= n; i++) {
            for (int j = i; j <= n; j++) {
                double sum = 0;
                for (int k = i; k <= j; k++)
                    sum += x[k];
                sum /= (j - i + 1);
                cost[i][j] = 0;
                for (int k = i; k <= j; k++)
                    cost[i][j] += (x[k] - sum) * (x[k] - sum);
            }
        }
        for (int i = 0; i <= n; i++) for (int j = 0; j <= m; j++) dp[i][j] = 1e9;
        dp[0][0] = 0;
        for (int i = 1; i <= n; i++) { // 枚举当前要放多少个包裹
            for (int j = 1; j <= i && j <= m; j++) { // 枚举仓库,要求仓库的数量比包裹数量少
                for (int k = j; k <= i; k++) {
                    // 枚举从第k个包裹到第i个包裹全都放到最后一个仓库,
                    // 而且满足前面的j-1个仓库都至少一个包裹
                    dp[i][j] = min(dp[i][j], dp[k-1][j-1] + cost[k][i]);
                }
            }
        }
        printf("%.2f
    ", dp[n][m]);
        return 0;
    }
    
    /*
    6 3
    1 3 7 9 10 16
    5 3
    1 3 7 9 10
    1 1
    5
    */
    
  • 相关阅读:
    dsu on tree
    bzoj3527 [Zjoi2014]力
    bzoj3527 [Zjoi2014]力
    114.遍历文件夹并批量修改文件名
    25.八皇后问题
    24.C语言最全排序方法小结(不断更新)
    112.备忘录设计模式
    110.文件搜索,系统大小获取,以及病毒行为
    109.vprintf vfprintf vscanf vfscanf
    108.sqllite3(C语言数据库库)详解
  • 原文地址:https://www.cnblogs.com/fightfordream/p/8674507.html
Copyright © 2011-2022 走看看