我申请这个blog是为了督促自己,把自己平时的一些想法和思考结果保留下来。 本博客所有内容均为原创,如有转载请注明作者和出处

用SQL解决两道有趣的题(二)

上一篇 / 下一篇  2008-01-03 09:47:25 / 个人分类:ORACLE

OracleSQL语句功能还是很强的,看到两道比较有趣的题,用SQL来尝试求解。

SQL解决两道有趣的题(一):http://yangtingkun.itpub.net/post/468/448940

 

 

第二个问题:

GaussPoincare在天堂相遇了,上帝说:你们都是人间最伟大的数学家,那我来出道题考考你们谁更聪明。我在左手写一个大于1小于100的数,在右手同样写一个大于1小于100的数,然后把他们的和写在Gauss手上,把积写在Poincare手上,看看你们能不能猜出这两个数字是几。
H q)H YBG0Gauss
看了手上的数字,说:我不知道这两个数字是几,可我保证Poincare也不知道。ITPUB个人空间5i ? _7Pk
Poincare
看了手上的数字,说:我原来的确不知道那两个数字是几,可我现在知道了。

4n)i ^a9fi.H-b0Gauss
说:那我也知道了。
ITPUB个人空间(bU0f#K$Z SK.e~1?
问题:那两个数字是几?

粗看上去似乎和刚才第一题很像,如果仔细研究就会发现二者的区别还是很大的,相比之下,这道题比第一题要难一些。

仍然是先给出SQL解,然后描述一下思路:

SQL> WITH T_NUM AS
A'z4EChw'p^0  2  (SELECT ROWNUM + 1 NUM FROM DUAL CONNECT BY LEVEL < 99)ITPUB个人空间+_h!eU]
  3  SELECT A, B
~2L?z h*U}S-}k~0  4  FROM
T"o j"qWX5X1PU;HU0  5  (ITPUB个人空间}W m0MT o*I `)db
  6   SELECT
7U/mK w H ?1z0  7    A,ITPUB个人空间1V0Dvwln
  8    B,ITPUB个人空间$VI U O*HC r2y-Y
  9    TOTAL,
} v xjg)NW0 10    MUL,ITPUB个人空间%n+I Tf]`/D_^
 11    MUL_P,ITPUB个人空间%C-inqA$`!Q8U5Y
 12    COUNT(DECODE(MUL_P, 1, 1)) OVER(PARTITION BY TOTAL) VALUE
^XB~'dx0 13   FROM
$zDD2m\hN_5}I0 14   (
:o e&p;`1_0 15    SELECT
'n_$P$z:Uw0 16     A,ITPUB个人空间"c9PC7eP*L
 17     B,
$mOp E"V0^ f0 18     TOTAL,
%m5m-h m D*? h!rm0 19     MUL,
6|EfK6vW a Z0 20     COUNT(*) OVER (PARTITION BY TOTAL) TOTAL_P,
qDe.}F[0 21     COUNT(*) OVER (PARTITION BY MUL) MUL_P
lRKzF7]F0 22    FROM
9x3t'q2VuF,TG0 23    (
xU$}S7|*K0 24     SELECTITPUB个人空间 G-` {qv[#p
 25      A,ITPUB个人空间D0P(WhYJ
 26      B,ITPUB个人空间c$ff/m7^(u8?9X+q6n*f
 27      TOTAL,ITPUB个人空间i1P2[)t,T$T
 28      MUL,ITPUB个人空间!^ `m-a o I7r
 29      MIN(MUL_P) OVER (PARTITION BY TOTAL) MUL_M
%z$o$?f\5g _,T0 30     FROMITPUB个人空间,d^,V!CRuk's
 31     (ITPUB个人空间v"eoHH K4m1b
 32      SELECTITPUB个人空间*h u$V$s*J|
 33       A.NUM A,ITPUB个人空间lXM9li'M
 34       B.NUM B,ITPUB个人空间 [W2Qx u#a e
 35       A.NUM + B.NUM TOTAL,ITPUB个人空间1Ur:kP7c
 36       A.NUM * B.NUM MUL,
ZFip~0 37       COUNT(*) OVER (PARTITION BY A.NUM + B.NUM) TOTAL_P,
:pm0}&^y$VT A0 38       COUNT(*) OVER (PARTITION BY A.NUM * B.NUM) MUL_P 
Yp'kD1? g;o0L0 39      FROM T_NUM A, T_NUM BITPUB个人空间FA1`R%[O
 40      WHERE A.NUM < B.NUM
IHm:lz:Y0 41     )
/W+R2qT9Lp3m$y0 42    ) 
F!@-_k[E` O Ps0hI0 43    WHERE MUL_M != 1
~&K1A+X(tI0 44   )
,L;G)I;G NkW%A0 45  )
V-pD z/F|V/V5u0 46  WHERE MUL_P = 1ITPUB个人空间]%V,aJ5o0K,T j&z
 47  AND VALUE = 1;

         A          B
$cGK[B.n$]iP0---------- ----------
$_ Eb!_!u$E'tzOX%L2a0         4         13

下面简单描述一下思路:

WITH语句就是构造一张基础数据表。

最内层的循环构造两个数的笛卡儿积,列出所有的可能,不过对于我们来说,A1B2A2B1没有区别,因此加上限制条件A > B。循环中的分析函数用来计算AB两个数的和相同的个数以及AB两个数的积相同的个数。

下面到了这道题和第一题的区别之处。Gauss不但自己不知道,还可以确认Poincare也不知道。这说明AB两个数构成Gauss手里的和TATOL不但不是唯一的,而且所有能构成这个TOTALAB的积MUL都不是唯一的。这就是第二层嵌套的含义。

到了第三层,过滤掉上面那些不符合条件的AB之后。要解决的问题就是Poincare知道AB的答案后,Gauss也知道了。

这说明对于TOTAL这个值,所有AB的组合中有一个且只有一个组合它们的乘积是唯一确定的。这是通过第四层嵌套中那个COUNT(DECODE) OVER实现的。

最后过滤乘积唯一,且对于相同TOTAL的所有AB组合中有且仅有一个乘积唯一确定的AB组合。

如果还是不明白,可以将这个嵌套一层层执行,观察每一步的执行结果,有助于理解每一步实现的目的。

 


TAG:

 

评分:0

我来说两句

显示全部

:loveliness: :handshake :victory: :funk: :time: :kiss: :call: :hug: :lol :'( :Q :L ;P :$ :P :o :@ :D :( :)

Open Toolbar