|
加上x0对x的优化,这下差不多了:
with
V as -- 点 (编号, 名称, 人数)
(
select ROWNUM n, A.c, NVL(B.members, 0) m
from (
select city1 c from routes
union
select city2 c from routes
ORDER BY 1
) A left join cities B on A.c = B.city_name
),
-- 边 (目标城市编号,开始城市编号,开始城市人数,两地距离)
E as
(
select VC.n cn, VF.n fn, VF.m fm, R.d
from (
select city1 c, city2 f, distance d from routes
union
select city2 c, city1 f, distance d from routes
) R, V VC, V VF
where R.c = VC.c And R.f = VF.c
),
--采样,预先计算4个,然后用计算出来的最小值去过滤X表的结果
--可能会过滤掉一些,如果运气不是太坏的话,但至少不会变得更坏
X0 (y, c, f, v, str) as --计算表 (层, 举办城市, 费用, 点标志,距离)
(
select distinct 1, c, 0 f,
--每个城市一个字符,标识城市是否已经在路径中
CAST(RPAD(LPAD('X', V.n),VN.n) AS VARCHAR2(1000)) v,
--每个城市10个字符,城市的距离(已经说了距离是整数,这里取10位,T-SQL中按int计算)
CAST(RPAD(LPAD(RPAD('0',10), V.n * 10),VN.n * 10) AS VARCHAR2(1000)) as s
from V, (select count(*) n from V) VN where V.n <= 4
union all
select
y + 1
,X.c
,X.f + 2* SUBSTR((SELECT MIN(LPAD(e.d + TO_NUMBER(TRIM(SUBSTR(X.str, (E.cn - 1) * 10 + 1, 10))),10)||LPAD(e.fn,10)||LPAD(e.fm,10)) FROM e where SUBSTR(X.v, E.cn, 1) = 'X' and SUBSTR(X.v, E.fn, 1) = ' '),1,10)
* SUBSTR((SELECT MIN(LPAD(e.d + TO_NUMBER(TRIM(SUBSTR(X.str, (E.cn - 1) * 10 + 1, 10))),10)||LPAD(e.fn,10)||LPAD(e.fm,10)) FROM e where SUBSTR(X.v, E.cn, 1) = 'X' and SUBSTR(X.v, E.fn, 1) = ' '),21,10)
,SUBSTR(X.v,1,SUBSTR((SELECT MIN(LPAD(e.d + TO_NUMBER(TRIM(SUBSTR(X.str, (E.cn - 1) * 10 + 1, 10))),10)||LPAD(e.fn,10)||LPAD(e.fm,10)) FROM e where SUBSTR(X.v, E.cn, 1) = 'X' and SUBSTR(X.v, E.fn, 1) = ' '),11,10)-1)
||'X'
||SUBSTR(X.v,SUBSTR((SELECT MIN(LPAD(e.d + TO_NUMBER(TRIM(SUBSTR(X.str, (E.cn - 1) * 10 + 1, 10))),10)||LPAD(e.fn,10)||LPAD(e.fm,10)) FROM e where SUBSTR(X.v, E.cn, 1) = 'X' and SUBSTR(X.v, E.fn, 1) = ' '),11,10)+1) v
,SUBSTR(X.str,1,(SUBSTR((SELECT MIN(LPAD(e.d + TO_NUMBER(TRIM(SUBSTR(X.str, (E.cn - 1) * 10 + 1, 10))),10)||LPAD(e.fn,10)||LPAD(e.fm,10)) FROM e where SUBSTR(X.v, E.cn, 1) = 'X' and SUBSTR(X.v, E.fn, 1) = ' '),11,10) - 1) * 10)
||SUBSTR((SELECT MIN(LPAD(e.d + TO_NUMBER(TRIM(SUBSTR(X.str, (E.cn - 1) * 10 + 1, 10))),10)||LPAD(e.fn,10)||LPAD(e.fm,10)) FROM e where SUBSTR(X.v, E.cn, 1) = 'X' and SUBSTR(X.v, E.fn, 1) = ' '),1,10)
||SUBSTR(X.str,(SUBSTR((SELECT MIN(LPAD(e.d + TO_NUMBER(TRIM(SUBSTR(X.str, (E.cn - 1) * 10 + 1, 10))),10)||LPAD(e.fn,10)||LPAD(e.fm,10)) FROM e where SUBSTR(X.v, E.cn, 1) = 'X' and SUBSTR(X.v, E.fn, 1) = ' '),11,10) - 1) * 10+11) s
from X0 X
WHERE y<(SELECT COUNT(*) FROM v)
) CYCLE V SET cycle_flag TO 'Y' DEFAULT 'N'
,F(n) as (select min(f) from X0 where y = (select count(*) from V))
,X (y, c, f, v, str) as --计算表 (层, 举办城市, 费用, 点标志,距离)
(
select distinct 1, c, 0 f,
--每个城市一个字符,标识城市是否已经在路径中
CAST(RPAD(LPAD('X', V.n),VN.n) AS VARCHAR2(1000)) v,
--每个城市10个字符,城市的距离(已经说了距离是整数,这里取10位,T-SQL中按int计算)
CAST(RPAD(LPAD(RPAD('0',10), V.n * 10),VN.n * 10) AS VARCHAR2(1000)) as s
from V, (select count(*) n from V) VN where V.n > 4
union all
select
y + 1
,X.c
,X.f + 2* SUBSTR((SELECT MIN(LPAD(e.d + TO_NUMBER(TRIM(SUBSTR(X.str, (E.cn - 1) * 10 + 1, 10))),10)||LPAD(e.fn,10)||LPAD(e.fm,10)) FROM e where SUBSTR(X.v, E.cn, 1) = 'X' and SUBSTR(X.v, E.fn, 1) = ' '),1,10)
* SUBSTR((SELECT MIN(LPAD(e.d + TO_NUMBER(TRIM(SUBSTR(X.str, (E.cn - 1) * 10 + 1, 10))),10)||LPAD(e.fn,10)||LPAD(e.fm,10)) FROM e where SUBSTR(X.v, E.cn, 1) = 'X' and SUBSTR(X.v, E.fn, 1) = ' '),21,10)
,SUBSTR(X.v,1,SUBSTR((SELECT MIN(LPAD(e.d + TO_NUMBER(TRIM(SUBSTR(X.str, (E.cn - 1) * 10 + 1, 10))),10)||LPAD(e.fn,10)||LPAD(e.fm,10)) FROM e where SUBSTR(X.v, E.cn, 1) = 'X' and SUBSTR(X.v, E.fn, 1) = ' '),11,10)-1)
||'X'
||SUBSTR(X.v,SUBSTR((SELECT MIN(LPAD(e.d + TO_NUMBER(TRIM(SUBSTR(X.str, (E.cn - 1) * 10 + 1, 10))),10)||LPAD(e.fn,10)||LPAD(e.fm,10)) FROM e where SUBSTR(X.v, E.cn, 1) = 'X' and SUBSTR(X.v, E.fn, 1) = ' '),11,10)+1) v
,SUBSTR(X.str,1,(SUBSTR((SELECT MIN(LPAD(e.d + TO_NUMBER(TRIM(SUBSTR(X.str, (E.cn - 1) * 10 + 1, 10))),10)||LPAD(e.fn,10)||LPAD(e.fm,10)) FROM e where SUBSTR(X.v, E.cn, 1) = 'X' and SUBSTR(X.v, E.fn, 1) = ' '),11,10) - 1) * 10)
||SUBSTR((SELECT MIN(LPAD(e.d + TO_NUMBER(TRIM(SUBSTR(X.str, (E.cn - 1) * 10 + 1, 10))),10)||LPAD(e.fn,10)||LPAD(e.fm,10)) FROM e where SUBSTR(X.v, E.cn, 1) = 'X' and SUBSTR(X.v, E.fn, 1) = ' '),1,10)
||SUBSTR(X.str,(SUBSTR((SELECT MIN(LPAD(e.d + TO_NUMBER(TRIM(SUBSTR(X.str, (E.cn - 1) * 10 + 1, 10))),10)||LPAD(e.fn,10)||LPAD(e.fm,10)) FROM e where SUBSTR(X.v, E.cn, 1) = 'X' and SUBSTR(X.v, E.fn, 1) = ' '),11,10) - 1) * 10+11) s
from X
WHERE y<(SELECT COUNT(*) FROM v)
AND X.f + 2* SUBSTR((SELECT MIN(LPAD(e.d + TO_NUMBER(TRIM(SUBSTR(X.str, (E.cn - 1) * 10 + 1, 10))),10)||LPAD(e.fn,10)||LPAD(e.fm,10)) FROM e where SUBSTR(X.v, E.cn, 1) = 'X' and SUBSTR(X.v, E.fn, 1) = ' '),1,10)
* SUBSTR((SELECT MIN(LPAD(e.d + TO_NUMBER(TRIM(SUBSTR(X.str, (E.cn - 1) * 10 + 1, 10))),10)||LPAD(e.fn,10)||LPAD(e.fm,10)) FROM e where SUBSTR(X.v, E.cn, 1) = 'X' and SUBSTR(X.v, E.fn, 1) = ' '),21,10)
<=(select n from F)
) CYCLE V SET cycle_flag TO 'Y' DEFAULT 'N'
,r AS (
SELECT *
FROM (SELECT x2.*
,RANK() OVER(ORDER BY f) RNK
FROM (SELECT * FROM X0 WHERE Y=(select count(*) from V)
UNION ALL
SELECT * FROM X WHERE Y=(select count(*) from V)
) x2
)
WHERE RNK=1
)
SELECT c1,NVL(c2,'TOTAL'),SUM(cost)
FROM (SELECT r.c c1, v.c c2, V.m * SUBSTR(r.str, (v.n - 1) * 10 + 1, 10) * 2 cost
FROM r,v
WHERE r.c<>v.c
)
WHERE cost>0
GROUP BY c1,ROLLUP(c2)
ORDER BY c1,c2 NULLS FIRST; |
|