zoukankan      html  css  js  c++  java
  • IOI2000 Post Office (POJ1160)

    前言

    昨天XY讲课!讲到这题!还是IOI的题!不过据说00年的时候DP还不流行。

    题面

    http://poj.org/problem?id=1160

    分析

     § 1 中位数

    首先我们考虑,若有x1 < x2 < ... < xn,则当∑abs(x - xi)最小时,x为x, x, ... , xn这n个数的中位数。

    证明如下:我们把x, x, ... , xn看作数轴上n个点,我们先考虑两端,要使abs(x - x1) + abs(x - xn)最小,那么x必定在x1和xn中间,这是个很显然的初中数学题。

    好,那么我们就可以置这两个点不管了;剩下的点我们也这样考虑,如此类推,最后要么剩下一个点,要么就是剩下两个点中间的一段区间,答案就显而易见了。证毕。

    (在July 1, 2018的AtCoder Contest 100 Task C Linear Approximation就是用这个思路,但是不知道为什么到比赛结束我还是WA,到时候也搞个这题的题解)

    § 2 给定一段村庄怎么放邮局

    我们要求每个村庄到邮局距离总和最近,那么给定一段区间里的村庄,我们要找到一个满足要求的村庄建邮局,由上面关于中位数的结论可知,建邮局的村庄就是这段村庄最中间的那个。

    § 3 动态规划

    既然我们知道,在一段给定的村庄下放邮局的最小花费,那么很容易想到一个区间DP的思路。

    DP[i][j]表示在编号为1~i的村庄中,建了j个邮局,所需的最小花费。

    这时转移方程已经非常明显了:

    DP[i][j] = min{ DP[k][j - 1] + cost[k + 1][i] }

    其中j - 1 <= k <= icost[l][r]表示在l到r的区间里建一个邮局所需花费。

    而cost是可以在O(n2)的时间内预处理出来的,那么时限是绝对绰绰有余了。

    参考代码

     1 // POJ1160
     2 // IOI2000
     3 // Post Office
     4 #include <cstdio>
     5 #include <algorithm>
     6 const int MAXV = 305, MAXP = 35, INF = 0x3f3f3f3f;
     7 
     8 int V, P, X[MAXV], DP[MAXV][MAXP], sum[MAXV][MAXV];
     9 
    10 int main() {
    11     scanf("%d%d", &V, &P);
    12     int i, j, k, lim;
    13     for (i = 1; i <= V; i++) scanf("%d", &X[i]);
    14     for (i = 1; i < V; i++)
    15         for (j = i + 1; j <= V; j++) sum[i][j] = sum[i][j - 1] + X[j] - X[i + j >> 1];  // 预处理cost,这里用sum写了
    16 //    DP[0][0] = INF;  // 这里注意DP[0][0]=0,但是DP[i][0]=INF,当i > 0时,因为这时候这个状态是没有意义的
    17     for (i = 1; i <= V; i++) {
    18         DP[i][0] = INF;
    19         lim = std::min(i, P);
    20         for (j = 1; j <= lim; j++) {
    21             DP[i][j] = INF;
    22             for (k = j - 1; k < i; k++) DP[i][j] = std::min(DP[i][j], DP[k][j - 1] + sum[k + 1][i]);
    23         }
    24     }
    25     printf("%d
    ", DP[V][P]);
    26     return 0;
    27 }

    总结

    如果放在现在,这大概就够个联赛题难度了。但是当年呢DP在算法竞赛中还不常用,所以当年要想到这个思路,是非常不容易了。

    讲题是zzd大佬还讲了一个很奇怪的方程:

    DP[i][j]表示前i个村庄,建了j个邮局,其中第i个村庄一定是邮局的最小花费。

    当然这个状态转移也不难写,但是要注意答案不是DP[V][P],而是DP[V + 1][P + 1]。(即加一个假村庄,假村庄上建一个假邮局,这样就会把前面n个村庄的花费也正常纳入了,当然要通过一些手段不计算假村庄的花费)

  • 相关阅读:
    javac编译java文件报错:“3: 错误: 编码 GBK 的不可映射字符 (0xB2)”
    java HelloWorld时报错:"找不到或无法加载主类"问题的解决办法
    MySQL下载、安装、配置(5.7.19版本)
    console报错:"-Djava.endorsed.dirs=D:apache-tomcat-9.0.7endorsed is not supported. Endorsed standards and standalone APIs in modular form will be supported via the concept of upgradeable modul"的原因及解决办法
    uDig配图与GeoServer添加Style
    ArcGIS统计栅格像元值并转换为矢量图层
    博客项目
    python(openpyxl)复制excel数据到另一个excel数据表
    python openpyxl自动化操作excel(xlsx)
    python自动化之 excel转word
  • 原文地址:https://www.cnblogs.com/CaptainSlow/p/9262312.html
Copyright © 2011-2022 走看看