|---|---|---|---|---| | 1 | 1 | 3 | 5 | 1 | |---|---|---|---|---| | 3 | 3 | 2 | 0 | 3 | |---|---|---|---|---| | 3 | 0 | 3 | 2 | 3 | |---|---|---|---|---| | 1 | 4 | 0 | 3 | 3 | |---|---|---|---|---| | 3 | 3 | 3 | 1 | 1 | |---|---|---|---|---| (Figura 1)
Il programma legge i dati dal file INPUT.TXT. Per prima cosa compare la somma delle cifre, seguita dalla cifra che si dovrà trovare nell'angolo in alto a sinistra: il file contiene quindi solo due righe. Ci sarà sempre almeno una soluzione possibile. Nel nostro esempio:
11 1
11351 14033 30323 53201 13313 11351 33203 30323 14033 33311 13313 13043 32303 50231 13331
program Ioi9413;
(* Per rendere pi— efficiente la ricerca delle soluzioni, il programma
inizialmente ricerca i numeri primi che soddisfano le condizioni
richieste e li dispone in una trie. Una trie Š un albero in cui ogni
nodo ha al pi— dieci figli, uno per ogni possibile cifra *)
const
maxprimi=10000;
nomefin='input-4.txt';
nomefout='myout-4.txt';
DEBUG=true;
type
ptrie=^trie;
trie=array ['0'..'9'] of ptrie;
direzione=(oriz,vert,diag1,diag2);
var
primi: longint; (* Numero di primi trovati *)
sc: byte; (* Somma delle cifre *)
pr: array [1..maxprimi] of longint; (* Array dei primi trovati *)
tg: ptrie; (* Trie contenente i primi di 5 cifre con somma sc *)
sk: array [1..5,1..5] of char; (* Soluzione corrente *)
fin,fout: text; (* File di input e di output *)
procedure instrie(s: string; var t: ptrie);
(* Inserisce la stringa s nella trie t *)
var i: char;
begin
if (t=nil) then
begin
new(t);
for i:='0' to '9' do t^[i]:=nil
end;
if (length(s)>0) then
instrie(copy(s,2,length(s)-1),t^[s[1]])
end;
function godown(s: string; t: ptrie): ptrie;
(* Restituisce un puntatore alla trie che si ottiene da t scendendo
lungo s *)
begin
if (t=nil) then godown:=nil
else
if (length(s)>0) then
godown:=godown(copy(s,2,length(s)-1),t^[s[1]])
else godown:=t
end;
function sommacar(s: string): byte;
(* Somma le cifre di s *)
var tot,i: byte;
begin
tot:=0;
for i:=1 to length(s) do
tot:=tot+ord(s[i])-ord('0');
sommacar:=tot
end;
procedure sieve;
(* Riempie l'array pr e la trie tg con i primi la cui somma di cifre
sia sc *)
var i,j: longint;
s: string;
primo: boolean;
begin
primi:=0; tg:=nil;
for i:=2 to 99999 do
begin
primo:=true;
for j:=1 to primi do
if (i mod pr[j]=0) then
begin
primo:=false;
break
end;
if (primo) then
begin
primi:=primi+1;
pr[primi]:=i;
str(i,s);
if (i>9999) and (sommacar(s)=sc) then
instrie(s,tg)
end
end
end;
function frammento(x,l: byte; d: direzione): string;
(* Restituisce la stringa ottenuta leggendo l caratteri dalla matrice
sk;
in particolare: se d=oriz, i primi l caratteri della riga x; se d=vert,
i primi l caratteri della colonna x; se d=diag1, i primi l caratteri
della diagonale \; se d=diag2, i primi l caratteri della diagonale
/ *)
var i: byte;
s: string;
begin
s:='';
case (d) of
oriz: for i:=1 to l do s:=s+sk[x,i];
vert: for i:=1 to l do s:=s+sk[i,x];
diag1: for i:=1 to l do s:=s+sk[i,i];
diag2: for i:=1 to l do s:=s+sk[6-i,i]
end;
frammento:=s
end;
procedure out;
(* Emette la soluzione sk sul file fout *)
var i,j: byte;
begin
for i:=1 to 5 do
begin
for j:=1 to 5 do
write(fout,sk[i,j]);
writeln(fout)
end;
writeln(fout);
if (DEBUG) then writeln('Emessa soluzione')
end;
procedure fill(i,j: byte);
(* Prova a riempire la posizione i,j in modo compatibile con i caratteri
gia' presenti e passa all'elemento successivo; riempie per colonna:
x.... x.... xxx.. xxxxx xxxxx
..... x.... xxx.. xxxx. xxxxx
..... --> ..... --> --> xx... --> --> xxxx. --> --> xxxxx
..... ..... xx... xxxx. xxxxx
..... ..... xx... xxxx. xxxxx
i=indice di riga, j=indice di colonna;
notate che quando i=j il frammento di diag1 Š gi… disponibile;
quando 6-i=j il frammento di diag2 Š disponibile solo se i=1 e j=5
*)
var t1,t2,t3,t4: ptrie;
c: char;
begin
t1:=godown(frammento(i,j-1,oriz),tg); (* Framm. orizzontale *)
t2:=godown(frammento(j,i-1,vert),tg); (* Framm. verticale *)
if (i=j) then
t3:=godown(frammento(0,i-1,diag1),tg); (* Framm. su diag1 *)
if (i=1) and (j=5) then
t4:=godown(frammento(0,4,diag2),tg); (* Framm. su diag2 *)
for c:='0' to '9' do
begin
if (t1<>nil) and (t1^[c]<>nil) and
(t2<>nil) and (t2^[c]<>nil) and
((i<>j) or ((t3<>nil) and (t3^[c]<>nil))) and
((i<>1) or (j<>5) or ((t4<>nil) and (t4^[c]<>nil))) then
begin
sk[i,j]:=c;
if (i<5) then fill(i+1,j)
else
if (j<5) then fill(1,j+1)
else out
end
end
end;
(*** MAIN ***)
begin
assign(fin,nomefin);
assign(fout,nomefout);
reset(fin);
readln(fin,sc);
read(fin,sk[1,1]);
if (DEBUG) then writeln('Somma cifre=',sc,' Cifra iniziale=',sk[1,1]);
rewrite(fout);
sieve;
if (DEBUG) then writeln('Sto per produrre le soluzioni');
fill(2,1);
close(fout)
end.