四人过桥问题的SQL解法

看了开发版的帖子,又没有忍住,简单写了一个SQL语句。关于问题的详细描述可以参考http://www.itpub.net/thread-1595264-1-1.html
传说中的微软面试题:
有一群人A,B,C,D (人数>=2)要在夜里走过独木桥过河,他们只有一把手电筒。四个人的速度不同,过河分别需要1,2,5,10分钟,桥上最多走两个人,两个人一起走时按速度慢的计算。过河一定要用手电筒。请问最快的方法是如何安排,需要几分钟?
例子输出:
A B,A,A C,A,A D 19
直接给出最终结果:

SQL> WITH C AS
  2  (SELECT NAME, TIME, POWER(2, ROWNUM - 1) POS FROM BRIDGE_CROSSING), 
  3  A AS
  4  (SELECT 0 RN, A.NAME || ' ' || B.NAME NAME, GREATEST(A.TIME, B.TIME) TIME, A.POS + B.POS POS
  5  FROM C A, C B
  6  WHERE A.NAME < B.NAME
  7  UNION ALL
  8  SELECT 1, NAME, TIME, POS FROM C),
  9  B (RN, NAME, TIME, POS) AS
 10  (SELECT 0 RN, CAST ('' AS VARCHAR2(4000)) NAME, 0, 0 POS FROM DUAL
 11  UNION ALL
 12  SELECT B.RN + 1, 
 13     B.NAME || ',' || A.NAME, 
 14     B.TIME + A.TIME, 
 15     DECODE(MOD(B.RN, 2), 0, B.POS + A.POS, B.POS - A.POS)
 16  FROM B, A
 17  WHERE MOD(B.RN, 2) = A.RN
 18  AND DECODE(MOD(B.RN, 2), 0, BITAND(B.POS, A.POS), BITAND(B.POS - A.POS, A.POS)) = 0)
 19  SELECT LTRIM(NAME, ',') NAME, TIME FROM 
 20  (SELECT NAME, TIME, RANK() OVER(ORDER BY TIME) RN 
 21  FROM B
 22  WHERE POS = POWER(2, 4) - 1)
 23  WHERE RN = 1; 
NAME                                 TIME
------------------------------ ----------
A B,A,C D,B,A B                        17
A B,B,C D,A,A B                        17

简单描述一下思路,通过构造一个POS列标识每个人的位置,比如1101表明ABD三个人都已经过桥了,如果POS的值达到15,则说明所有人都过桥。
这个递归WITH和以往的区别在于,两个人一起过桥和一个人回来送手电的处理规则是不同的,甚至连接数据都是不同的。这里采用将两个人过桥和一个人回来作为不同的记录插入到同一个表中,然后用不同的ID进行区别。随后的递归调用,无论是查询列,还是进行关联的时候都要进行条件的判断,判断当前是两个人过桥,还是一个人回来,从而进行不同的操作。

This entry was posted in ORACLE and tagged , , . Bookmark the permalink.

Leave a Reply

Your email address will not be published. Required fields are marked *