|
楼上的写法适用于固定两人的情形;t1包含着一个笛卡尔积,回程是没有做优化的,把所有已过河的人都尝试一遍。每次递归都包含了来和回两个步骤,所以从NAK(对岸的人名单)中挑选最快的还不够,还得加上本次要过河的两人,再从中筛选出最快的。
with t1 as (
select a.name na1, b.name nb1, c.name na2, c.time + b.time total_time, c.time
from bridge_crossing a, bridge_crossing b, bridge_crossing c
where a.time < b.time
),
t2(na1, nb1, na2, total_time, nak, path, time) as
(
-- start with
select na1,
nb1,
na2,
total_time,
cast(decode(na1, na2, nb1, na1) as varchar2(100)) nak,
cast(na1 || nb1 || na2 as varchar2(100)) path,
time
from t1
where na1 = na2
or nb1 = na2
union all
-- 搜索路径
select t1.na1,
t1.nb1,
t1.na2,
t1.total_time + t2.total_time,
replace(t2.nak || t1.na1 || t1.nb1, t1.na2, ''),
t2.path || '-' || t1.na1 || t1.nb1 || t1.na2 path,
t1.time
from t1, t2
where instr(t2.nak, t1.na1) = 0
and instr(t2.nak, t1.nb1) = 0 and (t1.na1 = t1.na2 or t1.nb1 = t1.na2 or instr(t2.nak, t1.na2) > 0)
------- 回程的人只考虑速度最快的
AND t1.na2=(SELECT MIN(name) KEEP(DENSE_RANK FIRST ORDER BY time) FROM bridge_crossing b WHERE INSTR(t2.nak, b.name)>0 OR b.name IN (t1.na1,t1.nb1))
)
-- 查询结果
SELECT path,time_spent FROM (
select substr(t2.path, 1, length(t2.path) - 1) path, total_time - time as time_spent,RANK() OVER(ORDER BY total_time - time) rnk
from t2
where length(nak) = (select count(1) - 1 from bridge_crossing)
)
WHERE rnk=1;
|
|