上周六的离散数学课上,我学到了一个比较有趣的东西:有序对的定义。在引入有序对之前,所有的东西都是以集合为基础的;因此当我们讨论到有序对的概念时,我们只能用集合的语言去描述它。如何用集合来叙述有序对<a,b>,使得<a,b>=<c,d>当且仅当a=c且b=d呢?集合本身的无序性给我们带来了相当大的困难。比如,大多数人可能会想到<a,b>:={a,{b}}。可惜这种定义方法是错误的。考虑集合{ {1}, {2} },则它既可以是<{1},2>,又可以表示<{2},1>。那么定义<a,b>:={a,{b,Ø}}呢?这样也不行,道理是一样的,{{1,Ø}, {2,Ø}}既可能是<{1,Ø},2>,又可能是<{2,Ø},1>。那么,到底应该怎样定义有序对呢?如何定义最简单呢?
几经尝试后我们发现,我们得用处于同一“层”的、元素个数不对称的集合来区别有序对中的两个元素。1914年,Norbert Wiener给出了有序对的第一个集合定义:<a,b> := { {{a},Ø}, {{b}} },这从根本上区别出了a和b的顺序。目前最常用的定义是由Kuratowski给出的:<a,b>:={{a},{a,b}}。下面我们来证明一下,这种定义满足我们的要求:<a,b>=<c,d>当且仅当a=c且b=d。当a=c且b=d时,由条件和定义有{{a},{a,b}}={{c},{c,d}},于是充分性显然成立。下面我们只需要说明必要性:若<a,b>=<c,d>,则一定能推出a=c以及b=d。
由我们的定义,<a,b>=<c,d>可以写作{{a},{a,b}}={{c},{c,d}},则∩{{a},{a,b}}=∩{{c},{c,d}},即{a}={c}。我们立即得到,a和c是相等的。于是,我们有<a,b>=<a,d>,即{{a},{a,b}}={{a},{a,d}}。两边同时取并集,有∪{{a},{a,b}}=∪{{a},{a,d}},整理出来就是{a,b}={a,d}。好了,现在如果a≠b,注意到b是属于{a,d}的,那么只可能是b=d;如果a=b呢,那么{a,b}={a,d}={a},则a、b、c、d都相等,结论依然成立。
大家自然会想到,上述结论能否扩展到多元的有序组呢?换句话说,我们能不能照葫芦画瓢,定义<a,b,c>:={{a},{a,b},{a,b,c}}呢?出人意料的是,这种定义是错误的,这将导致<x,x,y>=<x,y,y>之类的荒谬的结论。那么我们又该如何定义三元有序组呢?其实很简单,定义<a,b,c>:=<a,<b,c>>就是了。本文主要参考了Wikipedia上的相关词条,也参考了Charlesgao上的一些内容。
最近看到的另一些有趣的东西都来自于各位网友。网友multiple1902发布了一个原创的数学公式定理速查表,比起这个来要精简实用一些,更适合高中使用。
好友leimiaos分享了一道(可能比较火星的)C语言趣题:不用比较符(>, <, ==等)和跳转类控制结构(if, ?:, switch等),求两个int类型数中较大的一个。答案相当有趣,Ctrl+A前大家不妨先想一想。
int max(int x,int y)
{
int number[2]={x,y};
unsigned __int64 z=(__int64)x-y;
return number[z>>63];
}
很高兴又认识了一个搞ACM/ICPC的MM。在这里向她打个招呼。
sf
最后那个C的题..我也火星了-_-||
嗯,我的Firefox绝对爱上那个MM了,只要一打开她的的blog5秒内就会崩溃
原来还在上学?真是厉害啊!
那题挺赞…
我的想法应该很正常才对……直接用={{{a},1},{{b},2}}就行了么……便于推广,不过没那么优美就是了……
如果不要求个数的话{a,a-b,a-b}也可以。
还有感觉到数第3段应该是={a,}
:={a,}
(a,b,c):={a,(b,c)}
pchu:
这时候定义了自然数了吗?我记得还没有吧……
最后那道题直接用(a+b+abs(a-b))/2不行吗?
in case int is the largest integral type allowed in the system, you could get around overflow/underflow by comparing the sign bit of x and y. x – y overflows/underflows iff x and y are of different signs, so we could do it as
int max(int x, int y) {
int z[3] = {x, y, x};
unsigned int diff = x – y;
int signx = ((unsigned) x) >> 31;
int signy = ((unsigned) y) >> 31;
return z[(diff >> 31) + (signx ^ signy)];
}
和Lambda calculus的定义很相似嘛
我们也正好学到离散数学的这部分……
笛卡尔集,关系……
(a+b+|a-b|)/2
绝对值应该不能用吧,因为绝对值不属于普通的函数了,里面包含了逻辑判断了。
绝对值可以的,绝对值可以写成
unsigned __int64 abs(__int64 x)
{
return (-(x >> 63)) ^ x + (x >> 63);
}
哎呀,不能用 unsigned
(a+b)+|a-b|
———————
2
最后那道题让我想到了一个别人做的几个画板的比较大小的工具,就是用绝对值和加减乘除做的
“1914年,Norbert Wiener给出了有序对的第一个集合定义: := { {{a},Ø}, {{b}} }”
实际上{ {a,Ø}, {b} }就可以,他为什么要多加层括号呢?还是说他采用的是那种不讨论元素只讨论集合的记法?
最后一道题这么做:
#include
int main()
{
int i,j;
i=229;j=222;
printf(“%i”,i+(j-i)*!(i/j));
getch();
return 0;
}