子集算法的完整数学推导过程
2010-05-19 23:33 SeasonLee 阅读(4879) 评论(5) 编辑 收藏 举报前言
自从笔者的《从离散数学到编译原理--百姓网编程题后序》一文发布以后,得到众多网友的肯定和赞赏,你们的支持是笔者写blog的源动力。而同时也由于笔者的水平所限,有网友指出在《百姓网编程题后序》中存在着不严谨的数学证明过程,而这些确实是笔者粗心的过失,实在感到十分羞耻。为了不给读者造成误解,笔者决定撰写本文来对《百姓网编程题后序》中的数学证明给出补充,以消除读者心中的疑念。
本文假设读者有一定的离散数学(Discrete Mathematics)基础,特别是对数学逻辑(Mathematical Logic)和集合论(Set Theory)有一定的认识,否则本文会让你难于理解。由于大陆与港台在专用术语的翻译上存在一定差异,在一些大陆专用的中文术语中,我都会在后面加上英文的对照版本以及相应的wiki link,港台的读者可以通过wiki link来消除你对该中文术语的困惑。
在这里笔者要感谢国家。感谢网友ff1在《百姓网编程题后序》中指出的错误,没有您的意见反馈,笔者不会知道在文中所犯下的错误。同时希望您能在本文中继续给出您宝贵的意见。感谢wukegui同学在数学证明上给我的帮助,您让我学回很多遗忘已久的数学知识。感谢赖总,王建硕先生和mikster对本文的review和意见。
限于笔者水平,本文中的疏漏和错误在所难免,欢迎批评和指正。同时也希望能与您进行更多深入的交流,请联系我myonlylee@gmail.com或者@season_lee。
正确还是错误?
笔者曾在《百姓网编程题后序》一文中简单证明过以下等价关系对于集合成立。
原命题 | 等价命题 |
A ⊆ (B ∩ C) | (A ⊆ B) ∧ (A ⊆ C) |
A ⊆ (B ∪ C) | (A ⊆ B) ∨ (A ⊆ C) |
(A ∪ B) ⊆ C | (A ⊆ C) ∧ (B ⊆ C) |
(A ∩ B) ⊆ C | (A ⊆ C) ∨ (B ⊆ C) |
但是,以上等价命题都是成立的吗?
否。对于红色字体的2个命题,它们的等价命题并不成立,而另外2个黑色字体的等价命题是成立的。
为了证明等价命题不成立,我们只要能找到一个反例就可以了。
>>对于命题A ⊆ (B ∪ C) ⇔ (A ⊆ B) ∨ (A ⊆ C),考虑以下集合图。
在图中,集合A有一部分属于B,而另一部分属于C,在这种特殊情况下,(A ⊆ B)不成立,(A ⊆ C) 也不成立,而A ⊆ (B ∪ C)却是成立的,所以等价关系A ⊆ (B ∪ C) ⇔ (A ⊆ B) ∨ (A ⊆ C)是错误的。
>>对于命题(A ∩ B) ⊆ C ⇔ (A ⊆ C) ∨ (B ⊆ C),考虑以下集合图。
在图中,A,B,C完全不存在子集的关系,但是(A ∩ B) ⊆ C确实成立。而等价命题(A ∩ B) ⊆ C ⇔ (A ⊆ C) ∨ (B ⊆ C)是错误的。
重要推论和定律
下面是笔者自命名的表达式和推论,是不会在数学书籍或者文献中出现的,这些表达式名称是作为本文的数学约定,仅仅为了帮助读者的理解,将使用下划线来做标识,而数学定律均使用加粗字体来表示。
元在本文中,应该理解为维(dimension)或者变量(variable),它是对应于查询语句中的一个字段名称。
一元单项式,即 x > 10或者y < 5,而不含∪或者∩。
一元多项式,即 一个∩或者一个∪或者两者或者多个∩、∪组成的关于x的表达式,即(x>10∪x<5) ∩ ( x > 6 ∩ x < 9)。
一元多项并集式,即 一个∪或者多个∪组成的关于x的表达式,即 x > 10 ∪ x < 5。
一元多项交集式,即 一个∩或者多个∩组成的关于x的表达式,即 x > 6 ∩ x < 9。
下面是推论:
A ⊆ (B ∩ C) ⇔ (A ⊆ B) ∧ (A ⊆ C) 对于任意集合都成立。 (推论1)
(A ∪ B) ⊆ C ⇔ (A ⊆ C) ∧ (B ⊆ C) 对于任意集合都成立。 (推论2)
A ⊆ (B ∪ C) ⇔ (A ⊆ B) ∨ (A ⊆ C) 当且仅当B,C均为一元多项式(B、C不能描述同一个元)的时候成立,我们在下面称之为推论3。
(A ∩ B) ⊆ C ⇔ (A ⊆ C) ∨ (B ⊆ C) 当且仅当A,B均为一元多项式(A、B不能描述同一个元)的时候成立,我们在下面称之为推论4。
误区1
为什么A ⊆ (B ∪ C) ⇔ (A ⊆ B) ∨ (A ⊆ C)对于A,B,C为任意集合时不成立,而当且仅当B,C均为一元多项式时就成立?
首先回答“A ⊆ (B ∪ C) ⇔ (A ⊆ B) ∨ (A ⊆ C)对于A,B,C为任意集合时不成立”,其实在例图1中已经给出例子,也就是当A有一部分属于B,而另一部分属于C的时候,正如例图1中所示,A不属于B也不属于C,但是A却是B与C并集的子集。
然后“A ⊆ (B ∪ C) ⇔ (A ⊆ B) ∨ (A ⊆ C) 当且仅当B,C均为一元多项式”,其实这里不难理解B、C实际需要满足什么条件。如果B只作一维上(假设是x维)的约束,而C作另外一维上(假设是y维)的约束,那么A要属于B、C的并集,A只需要满足x维上的约束或者满足y维上的约束。
为帮助读者的理解,请考虑以下特例:
x>10 ∩ x < 30 ⊆ (x >0 ∩ x <= 15) ∪ (x>15 ∩ x < 40)
x>10 ∩ x < 30不是x >0 ∩ x <= 15的子集,也不是x>15 ∩ x < 40的子集,但是x>10 ∩ x < 30却是这两者的并集的子集。
就是说对于ab ⊆ mn ∩ pq的分拆,不管是ab ⊆ mn ∨ ab ⊆ pq还是ab ⊆ mn ∧ ab ⊆ pq,最终的布尔表达式都是FALSE,但事实上应该是TRUE的。所以A ⊆ (B ∪ C) ⇔ (A ⊆ B) ∨ (A ⊆ C) 并不是一个真命题,请慎用!同理(A ∩ B) ⊆ C ⇔ (A ⊆ C) ∨ (B ⊆ C)也不是一个真命题。
接下来,我将使用到一些集合论中的法则(你可以在《离散数学及其应用》一书中找到)。其中符号AC 表示A的绝对补集(Complement)。
幂等律(Idempotent Laws):
A ∩ A = A
A ∪ A = A
结合律(Associative Laws):
A ∩ (B ∩ C) = (A ∩ B) ∩ C
A ∪ (B ∪ C) = (A ∪ B) ∪ C
分配律(Distributive Laws):
A ∩ (B ∪ C) = (A ∩ B) ∪ (A ∩ C)
A ∪ (B ∩ C) = (A ∪ B) ∩ (A ∪ C)
重补集律(Complementation Law):
(AC )C = A
德·摩根律(De Morgan’s Laws):
(A ∪ B)C = AC ∩ BC
(A ∩ B)C = AC ∪ BC
子集的逆否律(读者可以使用归纳法把这个证明出来):
A ⊆ B ⇔ BC ⊆ AC
子集算法推导过程(了解过的朋友请跳过这一节)
由于推论3和推论4无法适用于集合的所有情况,所以在以下算法中,我们需要对查询表达式作特殊的处理,进行若干变换,最终转化成适用于推论3和推论4的多个表达式,再使用一元多项交集式与一元多项并集式的子集判断算法,以完成完整的子集判断。
我们要把任意的查询表达式化为(a ∩ b ∩ c ∩….) ∪ (d ∩ e ∩ f ∩….) ∪…..这样多个交集所组成的并集,把它称为标准式。注意对于式子中的a,b,c,d……都是一元单项式。
如 (x > 10 ∪ y < 5) ∩ z < 0:
的标准式为: (x > 10 ∩ z < 0) ∪ (y < 5 ∩ z < 0) 分配律
>>步骤1
假设集合A表示成 (a∩b) ∪ (c∩d),集合B表示成 (m∩n) ∪ (p∩q),要判断A ⊆ B ,则:
(a∩b) ∪ (c∩d) ⊆ (m∩n) ∪ (p∩q)
[(m ∩ n) ∪ (p ∩ q)]C ⊆ [(a ∩ b) ∪ (c ∩ d)]C 逆否律
(mC ∪ nC )∩(pC ∪ qC)⊆(aC ∪ bC)∩(cC ∪ dC) 德·摩根律
(mC ∩ pC )∪(mC ∩ qC)∪(nC ∩ pC)∪(nC ∩qC)⊆ (aC ∪bC)∩(cC ∪dC) 分配律
[mC ∩ pC ⊆ (aC ∪ bC )∩(cC ∪ dC )] ∧ [mC ∩ qC ⊆ (aC ∪ bC )∩(cC ∪ dC)] ∧ [nC ∩ pC ⊆ (aC ∪ bC )∩(cC ∪ dC ) ]∧ [nC ∩ qC ⊆ (aC ∪ bC )∩(cC∪ dC )] 推论1
>>步骤2
展开由于上式中是多项取逻辑与的关系,下面我们只考虑其中一项:
mC ∩ pC ⊆ (aC ∪bC )∩(cC ∪dC )
mC ∩ pC ⊆ (aC ∪ bC ) ∩ (cC ∪ dC )
(mC ∩ pC ⊆ aC ∪ bC )∧ (mC ∩ pC ⊆ cC ∪ dC ) 推论1(a ∩ b ⊆ m ∪ p) ∧ (c∩d ⊆ m∪p ) 逆否律
因此结合步骤1和步骤2,
我们可以把原式:
标准式
(a∩b) ∪ (c∩d) ⊆ (m∩n) ∪ (p∩q)
变换为:
中间式
(a ∩ b ⊆ m ∪ p) ∧ (c∩d ⊆ m∪p ) ∧ (a∩b ⊆ m∪q ) ∧ (c∩d ⊆ m∪q ) ∧ (a∩b ⊆ n∪p ) ∧ (c∩d ⊆ n∪p ) ∧ (a∩b ⊆ n∪q ) ∧ (c∩d ⊆ n∪q )
>>步骤3
我们着重考虑上面式子的一项a ∩ b ⊆ m ∪ p,因为a、b、m、p都是一元单项式。
假设a∩b和m∪p都是关于x,y的二元多项表达式。我们可以很轻松的合并元x,y:
a ∩ b ⊆ m ∪ p
[(x的多项交集式)∩(y的多项交集式)] ⊆ [(x的多项并集式)∪(y的多项并集式)]
下面X1表示x的x的多项交集式,用Y1表示y多项交集式,X2表示x的多项并集式,用Y2表示y的多项并集式。
a ∩ b ⊆ m ∪ p
X1∩Y1 ⊆ X2∪Y2
(X1∩Y1 ⊆ X2) ∨ (X1∩Y1 ⊆ Y2 ) 使用推论3和推论4
//Y1 ⊆ X2,Y1与X2并不是描述同一个元,所以不存在子集关系。
(X1 ⊆ X2) ∨ (Y1 ⊆ X2) ∨ (X1 ⊆ Y2) ∨ (Y1 ⊆ Y2)
(X1 ⊆ X2) ∨ (Y1 ⊆ Y2)
>>综述
根据步骤1、2、3,集合A:(a∩b) ∪ (c∩d),集合B:(m∩n) ∪ (p∩q),
A ⊆ B
标准式
[(a∩b) ∪ (c∩d)] ⊆ [(m∩n) ∪ (p∩q) ]
可以先化简为:
中间式
(a ∩ b ⊆ m ∪ p) ∧ (c∩d ⊆ m∪p ) ∧ (a∩b ⊆ m∪q ) ∧ (c∩d ⊆ m∪q ) ∧ (a∩b ⊆ n∪p ) ∧ (c∩d ⊆ n∪p ) ∧ (a∩b ⊆ n∪q ) ∧ (c∩d ⊆ n∪q )
再利用合并相同元的并集和交集:
最终式
[(X1 ⊆ X2) ∨ (Y1 ⊆ Y2)] ∧ [(V1 ⊆ V2) ∨ (W1 ⊆ W2)] ∧ [(J1 ⊆ J2) ∨ (K1 ⊆ K2)] ∧…...∧[(E1 ⊆ E2) ∨ (F1 ⊆ F2)]
上式的X1,Y1,V1,W1,J1,K1……E1,F1均为一元多项交集式,而X2,Y2,V2,W2,J2,K2……E2,F2均为一元多项并集集式。
浅谈一元多项交集式与一元多项并集式的子集判断。
在上一节中,我们把集合A与集合B的子集关系化简为:由一元多项交集式与一元多项并集式的子集关系,任意与或组合,形成的布尔表达式。
在下面我将浅谈一元多项交集式与一元多项并集式的子集判断。
举例:
一元多项交集式:集合A:x > 10 ∩ x > 15 ∩ x < 30……
一元多项并集式: 集合B: x>10 ∪ x>15 ∪ x< 30……
简单来讲集合A是表示一个区间,而集合B是表示多个区间,要判断 A ⊆ B,只需要遍历集合B中的所有区间,看是否能找到一个包含集合A的区间,如果找到则 A ⊆ B成立,如果找不到则A ⊆ B不成立。
下面使用伪代码(其实是python代码):
#集合A只包含一个区间
a_interval = set_A[0]
is_sub_set = False
for interval in set_B:
#a_interval 在 interval 里面
if is_sub_interval(a_interval, interval) == True:
is_sub_set = True
break
总结
1.主要由于推论3和推论4无法适用于集合的所有情况,所以在本文中,需要对查询表达式进行若干变换,最终转化成适用于推论3和推论4的多个表达式,再使用一元多项交集式与一元多项并集式的子集判断算法,以完成完整的子集判断。
2.推导过程比较繁琐,其实你只需要关注标准式--中间式--最终式之间的关系即可,推导过程只为了证明数学上的完备。
3.由于本文用到的算法比我在上篇中的算法要复杂多,限于本人水平和时间,暂时未能提供完整的程序代码。有兴趣的读者可以尝试把自己算法实现出来,并发布出来让大家参考参考。
更多
其实在原题下面的评论中,已经有不少更好的解法,下面我简单的说说。
mikster使用了多维空间的思想来描述了这道题,下面引用他本人的原话:
实际上是高维空间里的覆盖问题,离散化后逐个检查是朴素做法,复杂度取决于每次排除后的分裂速度。逆波兰是将空间立方体化的手段而已。如果高维线段树空间和速度都不好,所以朴素做法还是最好的,但是看起来还是不能满足要求
我比较怀疑这个问题的下限。
而另外一位朋友阿暖就使用了更为巧妙的中点检测法,对所有的区间作验证,有兴趣的朋友可以去看看:
A:(age>21)and(level>1)
B:(age>20)or(level>0)
首先 把每个字段分段
age :分成 [0 ,20 ,21] 三段
level :分成 [0, 1] 两端
这很容易实现
然后 每段取中点 作为测试值
age: [10,20.5,22]
level: [0.5,2]
然后 age*level 产生测试用例
放到A和B里测试
如果存在一个值属于A却不属于B......
怎么样 暴力吧
这叫乱拳打死老师傅
想想看 效率反而可能是最高的