hihoCoder #1157 建造金字塔

这道题我想了一天才想清楚做法。AC 了之后去看别人写的题解,都是三言两语意识流式描述,我并不能读懂。我觉得很自卑,为何人家解这道题如此轻松。不过,我还是决定把我的解法写下来,并且一定要写清楚。


思路

我想多数人见到这个题目的想法都是:先按照某种方式对三角形排序,再设法 DP 。大方向确实如此。我的做法是:「以三角形底边的右端点坐标为第一关键字从小到大,以三角形底边的左端点坐标为第二关键字从大到小」排序。记排序后的 \(n\) 个三角形为:\(T_1, T_2, \dots, T_n\) ,如此排序使得:

  1. 所有被 \(T_i\) 覆盖且不与 \(T_i\) 重合的三角形都排在 \(T_i\) 前面
  2. \(0 \le k< j < i \le n\)\(T_j \not\subseteq T_i, T_k \not\subseteq T_i\) 那么 \((T_k \cap T_{i}) \subseteq (T_j \cap T_i)\)

我不清楚是否还有别的排序方法也能满足上面两个条件,不过其他排序方法只要满足上述两性质,都可进而采用下面要讲的 DP 方法。

DP 状态 \(\DeclareMathOperator{\DP}{DP}\)

\(\DP_i\) 表示「只在前 \(i\) 个金字塔(即三角形)中选择一些建造并且一定建造第 \(i\) 座金字塔,所能获得的最大收益」。

边界条件

为了方便我们定义第 \(0\) 座金字塔为 \((-\infty, 0, 0)\)
边界条件为 \(\DP_0 = 0\)

转移方程

\[\DP_i = \max \left\\{ \DP_j + \sum_{j< k< i, T_k \subseteq T_i} T_k.w + T_i.w - \left | T_i \right | + \left| T_j \cap T_i\right|\right\\} \quad (0 \le j <i, T_j \not\subseteq T_i) \]

\(\left| T \right|\) 表示(等腰直角)三角形 \(T\) 的 面积。

复杂度 \(O(N^2)\)

这就是我的思路,当然还可以做一些小优化。代码就不贴了,我的目标是把思路说清楚,思路清楚了,代码并不难写。

总结

这道题目应当算作简单题,虽然我解得并不轻松。这个问题中,三角形其实可以简化为底边所表示的线段,设底边长为 \(l\),则三角行面积 \(s\) 可表为 \(s = s(l) =l^2/4\) 。这个问题可一般化为:给定若干条 \(x\) 轴上的线段,每条线段有一个收益值,另外给出一个成本函数 \(cost(l)\) 。其他部分和原具体问题相似,不赘述。

posted @ 2017-09-30 00:28  Pat  阅读(252)  评论(0编辑  收藏  举报