题解:
这题就是一个搜索,
用一个数组记录[i,j]所在的宫能否放K
用一个数组记录[i,j]所在的行能否放K
用一个数组记录[i,j]所在的列能否放K
这题的搜索回溯,应该只有60分
然后我们发现,将K从大到小,即9到1枚举,会剪掉很多不必要的搜索!
如下,但只有80分:
var
p:array [1..9,1..2,1..2] of longint;
a,b:array [0..10,0..10] of longint;
c:array [1..3,1..9,1..9] of boolean;
k,i,j,n,m,ans:longint;
procedure init;
begin
p[1,1,1]:=1; p[1,1,2]:=1; p[1,2,1]:=3; p[1,2,2]:=3;
p[2,1,1]:=1; p[2,1,2]:=4; p[2,2,1]:=3; p[2,2,2]:=6;
p[3,1,1]:=1; p[3,1,2]:=7; p[3,2,1]:=3; p[3,2,2]:=9;
p[4,1,1]:=4; p[4,1,2]:=1; p[4,2,1]:=6; p[4,2,2]:=3;
p[5,1,1]:=4; p[5,1,2]:=4; p[5,2,1]:=6; p[5,2,2]:=6;
p[6,1,1]:=4; p[6,1,2]:=7; p[6,2,1]:=6; p[6,2,2]:=9;
p[7,1,1]:=7; p[7,1,2]:=1; p[7,2,1]:=9; p[7,2,2]:=3;
p[8,1,1]:=7; p[8,1,2]:=4; p[8,2,1]:=9; p[8,2,2]:=6;
p[9,1,1]:=7; p[9,1,2]:=7; p[9,2,1]:=9; p[9,2,2]:=9;
end;
function zhi(aa,bb:longint):longint;
begin
if (aa=5) and (bb=5) then exit(10);
if (aa>=4) and (aa<=6) and (bb>=4) and (bb<=6) then exit(9);
if (aa>=3) and (aa<=7) and (bb>=3) and (bb<=7) then exit(8);
if (aa>=2) and (aa<=8) and (bb>=2) and (bb<=8) then exit(7);
exit(6);
end;
procedure dfs(x,y,dep:longint);
var
i,j:longint;
begin
if x>9 then
begin
if dep>ans then ans:=dep;
exit;
end;
if dep+10*9*(9*(9-x)+(9-y+1))<=ans then exit;
if a[x,y]>0 then
begin
if y=9 then dfs(x+1,1,dep+a[x,y]*b[x,y])
else dfs(x,y+1,dep+a[x,y]*b[x,y]);
end
else begin
for i:=9 downto 1 do
if not(c[1,x,i]) then
if not(c[2,y,i]) then
begin
for j:=1 to 9 do
if (x>=p[j,1,1]) and (x<=p[j,2,1]) and
(y>=p[j,1,2]) and (y<=p[j,2,2])
then break;
if not(c[3,j,i]) then
begin
c[1,x,i]:=true;
c[2,y,i]:=true;
c[3,j,i]:=true;
if y=9 then dfs(x+1,1,dep+i*b[x,y])
else dfs(x,y+1,dep+i*b[x,y]);
c[1,x,i]:=false;
c[2,y,i]:=false;
c[3,j,i]:=false;
end;
end;
end;
end;
begin
assign(input,'sudoku.in'); reset(input);
assign(output,'sudoku.out'); rewrite(output);
init;
for i:=1 to 9 do
begin
for j:=1 to 9 do
begin
read(a[i,j]);
b[i,j]:=zhi(i,j);
if a[i,j]>0 then
begin
c[1,i,a[i,j]]:=true;
c[2,j,a[i,j]]:=true;
for k:=1 to 9 do
if (i>=p[k,1,1]) and (i<=p[k,2,1]) and
(j>=p[k,1,2]) and (j<=p[k,2,2]) then break;
c[3,k,a[i,j]]:=true;
end;
end;
readln;
end;
ans:=-1;
dfs(1,1,0);
writeln(ans);
close(input); close(output);
end.
然后我们可以发现,如果一个枚举到的[i,j],它能放的K越少那么后面搜的也就可以大大剪枝!
所以加上上面的优化,就可以过了。
var
a,b,tp,op:array [0..10,0..10] of longint;
c:array [1..3,1..9,1..9] of boolean;
cp,kp,k,i,j,ans:longint;
function zhi(aa,bb:longint):longint;
begin
if (aa=5) and (bb=5) then exit(10);
if (aa>=4) and (aa<=6) and (bb>=4) and (bb<=6) then exit(9);
if (aa>=3) and (aa<=7) and (bb>=3) and (bb<=7) then exit(8);
if (aa>=2) and (aa<=8) and (bb>=2) and (bb<=8) then exit(7);
exit(6);
end;
procedure dfs(dep,rp:longint);
var
x,y,i,j,k,l,m:longint;
begin
if rp>81-kp then
begin
if dep>ans then ans:=dep;
exit;
end;
if dep+10*9*(81-rp-kp+1)<=ans then exit;
m:=10;
for i:=1 to 9 do
for j:=1 to 9 do
if op[i,j]=0 then
begin
l:=0;
for k:=1 to 9 do
if not(c[1,i,k]) then
if not(c[2,j,k]) then
if not(c[3,tp[i,j],k]) then inc(l);
if m>l then
begin
x:=i;
y:=j;
m:=l;
end;
end;
if (m<>10) and (m<>0) then
begin
op[x,y]:=1;
for i:=9 downto 1 do
if not(c[1,x,i]) then
if not(c[2,y,i]) then
if not(c[3,tp[x,y],i]) then
begin
c[1,x,i]:=true;
c[2,y,i]:=true;
c[3,tp[x,y],i]:=true;
dfs(dep+i*b[x,y],rp+1);
c[1,x,i]:=false;
c[2,y,i]:=false;
c[3,tp[x,y],i]:=false;
end;
op[x,y]:=0;
end;
end;
begin
for i:=1 to 9 do
begin
for j:=1 to 9 do
begin
read(a[i,j]);
b[i,j]:=zhi(i,j);
tp[i,j]:=(i-1) div 3*3+(j-1) div 3+1;
if a[i,j]>0 then
begin
c[1,i,a[i,j]]:=true;
c[2,j,a[i,j]]:=true;
c[3,tp[i,j],a[i,j]]:=true;
op[i,j]:=1;
kp:=kp+1;
cp:=cp+b[i,j]*a[i,j];
end;
end;
readln;
end;
ans:=-1;
dfs(0,1);
if ans<>-1 then writeln(ans+cp)
else writeln('-1');
end.