[해설및답변] 마방진쿼리 0 3 4,638

by 티그리스 마방진 [2012.01.31 20:01:01]



이번 문제는 쿼리문제라기보다는 마방진을 푸는 원리문제인거 같네요 ㅡㅡ

마농님이 접근한 방법을 봐도 알겠지만 마방진에도 일정한 패턴으로 풀수 있는 문제입니다. 고로 쿼리로 충분히 접근이 가능한 문제입니다.

5X5 마방진을 예로들어 설명하겠습니다.
15 2 19 6 23
22 14 1 18 10
9 21 13 5 17
16 8 25 12 4
3 20 7 24 11

1. 위 그림을 보면 중앙점(노란색)을 기준으로 바로위에 1번이 있습니다. 다른것도 확인해보면 항상 중앙점 바로위에 1이 존재합니다.

2. 1번을 시작으로 좌로 한칸 위로 한칸씩 이동하면서 1씩 증가합니다.(0일 경우 5번으로)

3. 한 사이클(5개씩, 7X7이면 7개씩)이 끝나고 위로 두칸씩 이동하면서 증가합니다.

이 3가지 패턴만으로 구할수 있는데요. 제가 첫번째로 접근한것은 각 사이클당 시작포인트를 구하는것입니다.
SELECT  LEVEL NO
    ,MOD((:NUM + 1) / 2 + LEVEL - 2,:NUM) + 1 X
    ,:NUM - MOD((:NUM + 1) / 2 + LEVEL - 1,:NUM) Y
FROM    DUAL
CONNECT 
   BY LEVEL <= :NUM
NO X Y
1 3 2 <== 1사이클 시작포인트
2 4 1 <== 2사이클 시작포인트
3 5 5 <== 3사이클 시작포인트
4 1 4 <== 4사이클 시작포인트
5 2 3 <== 5사이클 시작포인트

그 다음으로 각 시작점에서 값이 증가할수록 X를 -1 Y를 -1씩 차감합니다. 0일 경우 5로
SELECT  ((A.NO-1) * :NUM) + B.NO AS NO
     ,CASE WHEN A.X - B.MV > 0 THEN A.X - B.MV
       ELSE :NUM + (A.X - B.MV)
      END  AS X
     ,CASE WHEN A.Y - B.MV > 0 THEN A.Y - B.MV
       ELSE :NUM + (A.Y - B.MV)
      END  AS Y
FROM  (SELECT  LEVEL NO
        ,MOD((:NUM + 1) / 2 + LEVEL - 2,:NUM) + 1 X
        ,:NUM - MOD((:NUM + 1) / 2 + LEVEL - 1,:NUM) Y
     FROM    DUAL
     CONNECT 
       BY LEVEL <= :NUM) A
   ,(SELECT  LEVEL NO 
        ,LEVEL - 1 MV 
     FROM    DUAL 
     CONNECT 
       BY LEVEL <= :NUM) B
NO X Y
1 3 2
2 2 1
3 1 5
4 5 4
5 4 3
6 4 1
7 3 5
8 2 4
9 1 3
10 5 2
11 5 5
12 4 4
13 3 3
14 2 2
15 1 1
16 1 4
17 5 3
18 4 2
19 3 1
20 2 5
21 2 3
22 1 2
23 5 1
24 4 5
25 3 4

이후 작업은 마농님이 했던 11g이후의 listagg 또는 10g이후의 xmlagg 9i이후의 sys_connect_by_path(계층쿼리) 로 접근해서 풀어주시면 됩니다.
-- 9i 계층쿼리
SELECT  TRIM(MAX(SYS_CONNECT_BY_PATH(LPAD(NO,LENGTH(POWER(:NUM,2)),'0'),' '))) BANGGIN
FROM (SELECT  ((A.NO-1) * :NUM) + B.NO NO
        ,CASE WHEN A.X - B.MV > 0 THEN A.X - B.MV
          ELSE :NUM + (A.X - B.MV)
         END  X
        ,CASE WHEN A.Y - B.MV > 0 THEN A.Y - B.MV
          ELSE :NUM + (A.Y - B.MV)
         END  Y
   FROM  (SELECT  LEVEL NO
           ,MOD((:NUM + 1) / 2 + LEVEL - 2,:NUM) + 1 X
           ,:NUM - MOD((:NUM + 1) / 2 + LEVEL - 1,:NUM) Y
        FROM    DUAL
        CONNECT 
          BY LEVEL <= :NUM) A
      ,(SELECT  LEVEL NO 
           ,LEVEL - 1 MV 
        FROM    DUAL 
        CONNECT 
          BY LEVEL <= :NUM) B
   )
START WITH X = 1
CONNECT 
   BY PRIOR X = X - 1
  AND PRIOR Y = Y
GROUP 
   BY Y
ORDER 
   BY Y;
by 김정식 [2012.02.01 11:24:47]
마방진 패턴을 적용하면 되는 군요..
마방진 쿼리를 작성할 생각을 하다니 대단합니다.

by 마농 [2012.02.02 08:54:34]
정말 좋은 시도네요.
퀴즈 감사히 잘 풀었습니다.

by 티그리스 [2012.02.02 14:02:40]
풀어주셔서 감사합니다^^
댓글등록
SQL문을 포맷에 맞게(깔끔하게) 등록하려면 code() 버튼을 클릭하여 작성 하시면 됩니다.
로그인 사용자만 댓글을 작성 할 수 있습니다. 로그인, 회원가입