|
第二题附加题,一个SQL跑不出来,因为递归过程中很难去除重复。改用PLSQL可以得到结果:
----取出所有贴面的中心,共24点。
----把24种旋转放到一张小表
DROP table all_p;
create table all_p as
WITH d AS -------构造X,Y,Z的可能坐标
(SELECT LEVEL i FROM DUAL CONNECT BY LEVEL<=2
UNION ALL SELECT -LEVEL FROM DUAL CONNECT BY LEVEL<=2
)
,c AS ( --------用笛卡尔积得到所有坐标,为每个点赋予唯一编号。用字符做编号以便用TRANSLATE旋转
SELECT d1.i x,d2.i y,d3.i z,CHR(64+ROW_NUMBER() OVER(ORDER BY d1.i,d2.i,d3.i)) id
FROM d d1,d d2,d d3
WHERE d1.i IN (-2,2) AND d2.i NOT IN (-2,2) AND d3.i NOT IN (-2,2)
OR d1.i NOT IN (-2,2) AND d2.i IN (-2,2) AND d3.i NOT IN (-2,2)
OR d1.i NOT IN (-2,2) AND d2.i NOT IN (-2,2) AND d3.i IN (-2,2)
)
,r AS (-------把大立方体分别沿着X,Y,Z轴旋转90度。所有位置都可通过上述旋转叠加组合得来
SELECT template,MIN(template) OVER() original
FROM (
SELECT LISTAGG(id) WITHIN GROUP(ORDER BY x,y,z) template
FROM (
SELECT 1 as tpl_id,x,y,z,id -------原位不动
FROM c
UNION ALL
SELECT 2, x ,z ,-y,id -------沿着X轴上翻90度
FROM c
UNION ALL
SELECT 3, z ,y ,-x,id -------沿着Y轴上翻90度
FROM c
UNION ALL
SELECT 4, y ,-x ,z,id -------沿着Z轴顺时针翻90度
FROM c
)
GROUP BY tpl_id
)
)
,all_r(template,rn) AS ( --------叠加组合所有旋转
SELECT template,1 rn from r
UNION ALL
SELECT TRANSLATE(all_r.template,r.original,r.template)
,ROW_NUMBER() OVER(PARTITION BY TRANSLATE(all_r.template,r.original,r.template) ORDER BY 1) rn ---- 变换之后的位置可能有重复的,只留下任意一个
FROM all_r,r
WHERE all_r.rn=1 ---- 只留下任意一个
)
CYCLE template SET cycle_flag TO 'Y' DEFAULT 'N'
select rownum id,template,original from (
SELECT CAST(template AS VARCHAR2(30)) template,CAST(MIN(template) OVER() AS VARCHAR2(30)) original FROM all_r GROUP BY template
);
---------------------------
---- 构造最基本的六种扭转,把结果放到一张小表。
create table twist as
WITH d AS -------构造X,Y,Z的可能坐标
(SELECT LEVEL i FROM DUAL CONNECT BY LEVEL<=2
UNION ALL SELECT -LEVEL FROM DUAL CONNECT BY LEVEL<=2
)
,c AS ( --------用笛卡尔积得到所有坐标,为每个点赋予唯一编号。用字符做编号以便用TRANSLATE旋转
SELECT d1.i x,d2.i y,d3.i z,CHR(64+ROW_NUMBER() OVER(ORDER BY d1.i,d2.i,d3.i)) id
--,DENSE_RANK() OVER(ORDER BY DECODE(d1.i,:N,d1.i,-:N,d1.i),DECODE(d2.i,:N,d2.i,-:N,d2.i),DECODE(d3.i,:N,d3.i,-:N,d3.i)) AS COLOR
FROM d d1,d d2,d d3
WHERE d1.i IN (-2,2) AND d2.i NOT IN (-2,2) AND d3.i NOT IN (-2,2)
OR d1.i NOT IN (-2,2) AND d2.i IN (-2,2) AND d3.i NOT IN (-2,2)
OR d1.i NOT IN (-2,2) AND d2.i NOT IN (-2,2) AND d3.i IN (-2,2)
)
SELECT template,(SELECT LISTAGG(id) WITHIN GROUP(ORDER BY x,y,z) FROM c) original
FROM (
SELECT LISTAGG(id) WITHIN GROUP(ORDER BY x,y,z) template
FROM (
-- SELECT 1 as tpl_id,x,y,z,id FROM c -------原位不动
-- UNION ALL
SELECT 2 as tpl_id, CASE WHEN z IN (1,2) THEN y ELSE x END x,CASE WHEN z IN (1,2) THEN -x ELSE y END y,z,id FROM c ------- 上层扭90度
UNION ALL
SELECT 3, CASE WHEN z IN (-1,-2) THEN y ELSE x END,CASE WHEN z IN (-1,-2) THEN -x ELSE y END,z,id FROM c ------- 下层扭90度
UNION ALL
SELECT 4, x,CASE WHEN x IN (-1,-2) THEN -z ELSE y END,CASE WHEN x IN (-1,-2) THEN y ELSE z END,id FROM c ------- 左层扭90度
UNION ALL
SELECT 5, x,CASE WHEN x IN (1,2) THEN -z ELSE y END,CASE WHEN x IN (1,2) THEN y ELSE z END,id FROM c ------- 右层扭90度
UNION ALL
SELECT 6, CASE WHEN y IN (-1,-2) THEN -z ELSE x END,y,CASE WHEN y IN (-1,-2) THEN x ELSE z END,id FROM c ------- 前层扭90度
UNION ALL
SELECT 7, CASE WHEN y IN (1,2) THEN -z ELSE x END,y,CASE WHEN y IN (1,2) THEN x ELSE z END,id FROM c ------- 后层扭90度
)
GROUP BY tpl_id
)
;
---------------------------
---- 存放结果
create table all_t (position varchar2(30) NOT NULL,lvl NUMBER);
DECLARE
t1 date;
i number :=1;
BEGIN
delete all_t;
insert into all_t(position,lvl) SELECT original,0 FROM all_p WHERE ROWNUM=1;
LOOP
------- 每次循环做一次扭转,所有花色都可通过六种基本扭转叠加组合而来
------- 扭转后去除旋转的重复结果,只留下一种
t1 := sysdate;
INSERT INTO all_t(position,lvl)
WITH tmp AS (
SELECT DISTINCT (SELECT MIN(TRANSLATE(TRANSLATE(all_t.position,t.original,t.template),all_p.original,all_p.template)) FROM all_p) position
FROM all_t,twist t
where all_t.lvl=i-1
)
SELECT position,i FROM tmp WHERE position NOT IN (SELECT position FROM all_t);
EXIT when SQL%ROWCOUNT=0;
DBMS_OUTPUT.PUT_LINE('insert lvl='||i||' rows:'||SQL%ROWCOUNT||' seconds:'||round((sysdate-t1)*24*60*60,2));
DBMS_APPLICATION_INFO.SET_CLIENT_INFO('insert lvl='||i||' rows:'||SQL%ROWCOUNT||' seconds:'||round((sysdate-t1)*24*60*60,2));
i:=i+1;
COMMIT;
END LOOP;
END;
/
insert lvl=1 rows:6 seconds:0
insert lvl=2 rows:27 seconds:0
insert lvl=3 rows:120 seconds:0
insert lvl=4 rows:534 seconds:0
insert lvl=5 rows:2256 seconds:0
insert lvl=6 rows:8969 seconds:0
insert lvl=7 rows:33058 seconds:1
insert lvl=8 rows:114149 seconds:3
insert lvl=9 rows:360508 seconds:12
insert lvl=10 rows:930588 seconds:38
insert lvl=11 rows:1350852 seconds:80
insert lvl=12 rows:782536 seconds:108
insert lvl=13 rows:90280 seconds:66
insert lvl=14 rows:276 seconds:10
PL/SQL procedure successfully completed.
Elapsed: 00:05:18.80
jsu@JSU12P> select count(*) from all_t;
COUNT(*)
----------
3674160
|
|