이번 문제는 쿼리문제라기보다는 마방진을 푸는 원리문제인거 같네요 ㅡㅡ
마농님이 접근한 방법을 봐도 알겠지만 마방진에도 일정한 패턴으로 풀수 있는 문제입니다. 고로 쿼리로 충분히 접근이 가능한 문제입니다.
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;