トップページに戻る
次のPL/SQLの問題へ
前のPL/SQLの問題へ
Java版
PL/SQL4 (行儀の良い)ナイト巡回問題
SQLパズル
バックトラック法
ナイト巡回問題は、与えられたマスを、ナイトが連続して飛び続けることで、
全てのマスを1回ずつ訪れる経路を求める問題である。
行儀の良いナイト巡回問題では、最後に元に戻れるように巡回する。
つまり、最後のマスから、最初のマスへは「ナイト飛び」で移動できるものを指す。
行儀の良いナイト巡回問題を解いてみます。
SQL
create table goodKnightResult as
select sys_connect_by_path(to_char(X) || to_char(Y),'-') as path
from ban
where connect_by_IsLeaf = 1
and Level = 25
and (X=3 and Y=2
or X=2 and Y=3)
Start With 1 = all(X,Y)
connect by nocycle (prior X,prior Y)
in ((X+2,Y-1),(X+2,Y+1),
(X-2,Y+1),(X-2,Y-1),
(X+1,Y+2),(X+1,Y-2),
(X-1,Y+2),(X-1,Y-2));
PL/SQL
declare
masu constant pls_Integer := 5;
type InfoDef is record(
X pls_Integer,
Y pls_Integer,
LV pls_Integer,
Path varchar2(1000)
);
stackP pls_Integer := 0;
type StackClass is table of InfoDef index by binary_integer;
st StackClass;
StaInfo InfoDef;
priInfo InfoDef;
willPush InfoDef;
work varchar2(20);
isOK boolean;
procedure push(pInfoDef InfoDef) is
begin
st(stackP) := pInfoDef;
stackP := stackP+1;
end;
function pop return InfoDef is
begin
stackP := stackP-1;
return st(stackP);
end;
function isEmpty return boolean is
begin
return stackP = 0;
end;
begin
StaInfo.X := 1; StaInfo.Y := 1;
StaInfo.LV := 1; StaInfo.Path := '(1,1)';
push(StaInfo);
while (isEmpty = false) loop
priInfo := pop();
for X in 1..masu Loop
for Y in 1..masu Loop
if (((priInfo.X+2 = X and priInfo.Y+1 = Y)
or (priInfo.X+2 = X and priInfo.Y-1 = Y)
or (priInfo.X+1 = X and priInfo.Y+2 = Y)
or (priInfo.X+1 = X and priInfo.Y-2 = Y)
or (priInfo.X-2 = X and priInfo.Y+1 = Y)
or (priInfo.X-2 = X and priInfo.Y-1 = Y)
or (priInfo.X-1 = X and priInfo.Y+2 = Y)
or (priInfo.X-1 = X and priInfo.Y-2 = Y)) and priInfo.LV < masu*masu) then
work := '(' || to_char(X) || ',' || to_char(Y) || ')';
--未到着ノードならpush
if (instr(priInfo.Path,work) = 0) then
willPush.Path:= priInfo.Path || '-' || work;
willPush.X := X; willPush.Y := Y;
willPush.LV := priInfo.LV+1;
push(willPush);
end if;
end if;
end Loop;
end Loop;
--合格経路なら表示
if (priInfo.LV = masu*masu) then
isOK := true;
for X in 1..masu Loop
for Y in 1..masu Loop
work := '(' || to_char(X) || ',' || to_char(Y) || ')';
if (instr(priInfo.Path,work) = 0) then
isOK := false;
end if;
end Loop;
end Loop;
if (priInfo.X = 3 and priInfo.Y = 2
or priInfo.X = 2 and priInfo.Y = 3) then
null;
else
isOK := false;
end if;
if (isOK) then
DBMS_Output.Put_Line(priInfo.Path);
end if;
end if;
end Loop;
end;
/
解説
条件を満たす経路は存在しませんでした。