关于 P2123 【皇后游戏】错解的一些讨论以及一种不同的做法

ouuan

2018-10-31 16:37:06

Solution

[题目地址](https://www.luogu.org/problemnew/show/P2123) [相关文章](https://ouuan.github.io/浅谈邻项交换排序的应用以及需要注意的问题/) ## 内容简介 1. 详细说明直接比较 $\min(a_i,b_j)$ 和 $\min(a_j,b_i)$ 为什么是错的。 2. 给出一(实际上是两)种无需 $d_i=sgn(a_i-b_i)$ 的做法。 3. 给出一份判断一个比较方式是否是正解的代码。 所以,看懂本篇题解并不是解题所必要的,事实上本篇题解并没有讲如何推导出贪心式,这部分其它题解已经讲得很详细了。 但如果能看懂本篇题解的思想,并亲自推一遍,一定会有不小的收获。 本篇题解公式极多,等号极多,下标极多,难免手误,还请指出。 ## Part0 看本篇题解需要对`Strict Weak Ordering`有所了解,可以参考[这篇博客](https://www.cnblogs.com/walkerlala/p/5561339.html)。 简单来说,$\rm STL$ 的任何比较函数(包括但不限于使用`std::sort`、`std::lower_bound`、`std::priority_queue`时重载的小于号),都需要满足以下四个条件:(用 $<$ 表示重载的运算符) 1. $x\not<x$ (非自反性) 2. 若 $x<y$,则 $y\not<x$ (非对称性) 3. 若 $x<y,y<z$,则 $x<z$ (传递性) 4. 若 $x\not<y,y\not<x,y\not<z,z\not<y$,则 $x\not<z,z\not<x$ (不可比性的传递性) 事实上可以由 $1$ 和 $3$ 推出 $2$ 。 ## Part1 这部分严格地证明了不能直接比较 $\min(a_i,b_j)$ 和 $\min(a_j,b_i)$ ### 一、 为什么比较时不能加等号,即为什么不能是 $\min(a_i,b_j)\le \min(a_j,b_i)$。 因为如果加了等号,$\min(a_i,b_i)\le \min(a_i,b_i)$,不满足非自反性。 ### 二、 为什么不加等号也是错的呢?~~因为有hack数据~~ ``` 2 7 6 3 1 1 7 3 1 1 1 6 1 1 6 10 7 6 10 1 1 6 3 1 1 7 3 1 1 1 6 ``` ``` 26 26 ``` 在[这篇题解](https://www.luogu.org/blog/liuzibujian/solution-p2123)中提到了: ``` 错误的根本原因就是,这个判断条件不满足传递性。 ``` 实际上这个判断条件满足传递性,但不满足不可比性的传递性。 ### 满足传递性的证明: 命题:$\forall \begin{cases}\min(a_i,b_j)<\min(a_j,b_i)\\\min(a_j,b_k)<\min(a_k,b_j)\end{cases}$,有 $\min(a_i,b_k)<\min(a_k,b_i)$。 将上式拆解成逻辑式,即证: $\forall \begin{cases}(a_i<a_j\lor b_j<a_j)\land(a_i<b_i\lor b_j<b_i)\\(a_j<a_k\lor b_k<a_k)\land(a_j<b_j\lor b_k<b_j)\end{cases}$,有 $(a_i<a_k\lor b_k<a_k)\land(a_i<b_i\lor b_k<b_i)$。 假设原命题不成立,即 $\exists\begin{cases}(a_i<a_j\lor b_j<a_j)\land(a_i<b_i\lor b_j<b_i)\quad(1)\\(a_j<a_k\lor b_k<a_k)\land(a_j<b_j\lor b_k<b_j)\quad(2)\\(a_i\ge a_k\land b_k\ge a_k)\lor(a_i\ge b_i\land b_k\ge b_i)\quad(3)\end{cases}$ 分别讨论 $(3)$ 式成立的两种情况: 若 $a_i\ge a_k\land b_k\ge a_k$,由 $(2)$ 式得 $a_j<a_k$,进而推出 $a_j<a_i$,再由 $(1)$ 式得 $b_j<a_j$,再由 $(2)$ 式得到 $b_k<b_j$,所以 $b_k<b_j<a_j<a_k$,与 $b_k\ge a_k$ 矛盾,不成立。 若 $a_i\ge b_i\land b_k\ge b_i$,与上面类似,由 $(1)$ 式得 $b_j<b_i$,进而推出 $b_j<b_k$,再由 $(2)$ 式得到 $a_j<b_j$,再由 $(1)$ 式得到 $a_i<a_j$,所以 $a_i<a_j<b_j<b_i$,与 $a_i\ge b_i$ 矛盾,不成立。 综上所述,假设不成立。 所以,$P_{i,j}=\min(a_i,b_j)<\min(a_j,b_i)$ 具有传递性。 ### 不具有不可比性的传递性的证明: 命题:$\forall \begin{cases}\min(a_i,b_j)=\min(a_j,b_i)\\\min(a_j,b_k)=\min(a_k,b_j)\end{cases}$,有 $\min(a_i,b_k)=\min(a_k,b_i)$。 很明显,当 $a_j=b_j$ 且都很小时存在反例,如: $\begin{array}{c|c|c}&a&b\\i&3&5\\j&1&1\\k&2&7\end{array}$ $\begin{cases}\min(3,1)=\min(1,5)\\\min(1,7)=\min(2,1)\end{cases}$,但 $\min(3,7)\ne \min(2,5)$。 这样的反例还有很多,所以,$P_{i,j}=\min(a_i,b_j)<\min(a_j,b_i)$ 不具有不可比性的传递性。 ### 三、 总结:$P_{i,j}=\min(a_i,b_j)<\min(a_j,b_i)$ 不满足`Strict Weak Ordering`的要求,不能作为`std::sort`的比较函数。 ## Part2 真的需要用 $d_i=sgn(a_i-b_i)$ 来分组比较吗?当然是不用的,而且个人认为像[这篇题解](https://www.luogu.org/blog/namasikanam/solution-p2123)这样做很不自然..起码我是想不到这种神奇的做法的QAQ. 上面写了一大堆公式,是不是已经有人已经跑路了..现在开始讲一些纯贪心内容。 比较相邻两项时,若 $\min(a_i,b_j)=\min(a_j,b_i)$ ,从全局来看,把 $a$ 更小的放前面是不会更差的。所以得到另一个排序方式: $P^{'}_{i,j}=\begin{cases}a_i<a_j\quad(\min(a_i,b_j)=\min(a_j,b_i))\\\min(a_i,b_j)<\min(a_j,b_i)\quad(otherwise)\end{cases}$ ~~讲完了短暂的贪心,又要开始证明了~~ ### 满足非自反性: $\min(a_i,b_i)=\min(a_i,b_i)$,$a_i\not <a_i$。 ### 满足非对称性: 当 $\min(a_i,b_j)<\min(a_j,b_i)$ 时,$\min(a_j,b_i)\not <\min(a_i,b_j)$。 当 $\min(a_i,b_j)=\min(a_j,b_i),a_i<a_j$ 时,$\min(a_j,b_i)=\min(a_i,b_j),a_j\not <a_i$。 ### 满足传递性和不可比性的传递性: 一开始我想像上面那样分类讨论做..然后差点就把这篇文章弃坑了.. ~~后来才想起来我是OIer不是MOer~~ ``` #include <iostream> #include <cstdio> #include <algorithm> using namespace std; bool cmp(int x,int y); int a[10],b[10]; int main() { for (a[0]=1;a[0]<=6;++a[0]) { for (b[0]=1;b[0]<=6;++b[0]) { if (cmp(0,0)) { printf("No irreflexivity:%d %d\n",a[0],b[0]); } for (a[1]=1;a[1]<=6;++a[1]) { for (b[1]=1;b[1]<=6;++b[1]) { if (cmp(0,1)&&min(a[0],b[1])>min(a[1],b[0])) { printf("Not the best:%d %d %d %d\n",a[0],b[0],a[1],b[1]); } for (a[2]=1;a[2]<=6;++a[2]) { for (b[2]=1;b[2]<=6;++b[2]) { if (cmp(0,1)&&cmp(1,2)&&!cmp(0,2)) { printf("No transitivity:%d %d %d %d %d %d\n",a[0],b[0],a[1],b[1],a[2],b[2]); } if (!cmp(0,1)&&!cmp(1,0)&&!cmp(1,2)&&!cmp(2,1)&&(cmp(0,2)||cmp(2,0))) { printf("No transitivity of incomparability:%d %d %d %d %d %d\n",a[0],b[0],a[1],b[1],a[2],b[2]); } } } } } } } return 0; } bool cmp(int x,int y) { return min(a[x],b[y])==min(a[y],b[x])?a[x]<a[y]:min(a[x],b[y])<min(a[y],b[x]); } ``` 运行,什么都没发生??那就对了! 这说明 $P^{'}_{i,j}=\begin{cases}a_i<a_j\quad(\min(a_i,b_j)=\min(a_j,b_i))\\\min(a_i,b_j)<\min(a_j,b_i)\quad(otherwise)\end{cases}$ 既满足`strict weak ordering`,又保证排好序后替换邻项不会更优,是一个可以解决这道题目的排序方式。 事实上,更改上面给出的代码中的`cmp`,若没有任何输出即可作为本题的比较函数。 可以利用上面的代码快速验证: - $P_{i,j}=\min(a_i,b_j)<\min(a_j,b_i)$ 不具有不可比性的传递性。 - $P^{''}_{i,j}=\begin{cases}b_i>b_j\quad(\min(a_i,b_j)=\min(a_j,b_i))\\\min(a_i,b_j)<\min(a_j,b_i)\quad(otherwise)\end{cases}$ 是这题另一个可行的比较方式。 - $P^{'''}_{i,j}=\begin{cases}a_i>a_j\quad(\min(a_i,b_j)=\min(a_j,b_i))\\\min(a_i,b_j)<\min(a_j,b_i)\quad(otherwise)\end{cases}$ 不具有传递性。