OSDN Git Service

upd: greedy.md
authorgoldimax <goldimax1688@gmail.com>
Thu, 30 Aug 2018 13:34:31 +0000 (21:34 +0800)
committergoldimax <goldimax1688@gmail.com>
Thu, 30 Aug 2018 13:34:31 +0000 (21:34 +0800)
docs/basic/greedy.md

index 865e65b..e79dc67 100644 (file)
 
 1. 运用反证法,如果交换方案中任意两个元素/相邻的两个元素后,答案不会变得更好,那么可以发现目前的解已经是最优解了。
 2. 运用归纳法,先手算得出边界情况(例如 $n = 1$)的最优解 $F_1$,然后再证明:对于每个 $n$,$F_{n+1}$ 都可以由 $F_{n}$ 推导出结果。
+
+## 排序法
+
+用排序法常见的情况是输入一个包含几个(一般一到两个)权值的数组,通过排序然后遍历模拟计算的方法求出最优值。
+
+有些题的排序方法非常显然,如[LG1209](https://www.luogu.org/problemnew/show/P1209)就是将输入数组差分后排序模拟求值。
+
+然而有些时候很难直接一下子看出排序方法,比如[LG1080](https://www.luogu.org/problemnew/show/P1080)就很容易凭直觉而错误地以a或b为关键字排序,过样例之后提交就发现WA了QAQ。一个 ~~众所周知的~~ 常见办法就是尝试交换数组相邻的两个元素来**推导**出正确的排序方法。我们假设这题输入的俩个数用`struct { int a, b; } v[n];`来保存,用`m`表示`i`前面所有的`a`的乘积,那么第`i`个大臣得到的奖赏就是`m / v[i].b`,第`i + 1`个大臣得到的奖赏就是`m * v[i].a / v[i + 1].b`。如果我们交换第`i`个大臣与第`i + 1`个大臣的位置,那么第`i + 1`个大臣得到的奖赏就是`m / v[i + 1].b`,第`i + 1`个大臣得到的奖励就是`m * v[i + 1].a / v[i].b`。如果交前更优当且仅当`max(m / v[i].b, m * v[i].a / v[i + 1].b) < max(m / v[i + 1].b, m * v[i + 1].a / v[i].b)`,提取出相同的`m`并约分得到`max(1 / v[i].b, v[i].a / v[i + 1].b) < max(1 / v[i + 1].b, v[i + 1].a / v[i].b)`,然后分式化成整式得到`max(v[i + 1].b, v[i].a * v[i].b) < max(v[i].b, v[i + 1].a * v[i + 1].b)`,于是我们就成功得到排序函数了!
+
+```c++
+struct uv {
+    int a, b;
+    bool operator<(const uv &x) const {
+        return max(x.b, a * b) < max(b, x.a * x.b);
+    }
+};
+```
+
+
+
+~~看上去是不是很简单呢(这题高精度卡常……)~~ ,如果看懂了就可以尝试下一道类似的题[LG2123](https://www.luogu.org/problemnew/show/P2123)(请不要翻题解……。
+