早教吧作业答案频道 -->其他-->
noip2009靶形数独讲讲算法思想,就是思路
题目详情
noip2009靶形数独
讲讲算法思想,就是思路
讲讲算法思想,就是思路
▼优质解答
答案和解析
这个问题嘛,果断是DFS,就是深搜啦...
基本思想:一共9*9=81个格,每个格如果没有数就for t:=1 to 9 do 检查是否可填t,填入、递归,如果搜到了第82层,也就是完成了一个数独,就算一下,更新最大值.搜完后输出最大值就ok了.
不过这个是果断过不了的.
如果你刚刚学DFS,估计你能过6个点也就可以了(一共20个点啊);
如果你比较熟练了,就加些优化,大概可以过15个点(已经很不错了);
如果再加卡时的话,大概最好能过18个点(这是正着搜);
接下来你就知道该干啥了吧——
呵呵...倒着搜哈(也可以随机搜额)...这样大概就可以AC了(但这个果断是利用了数据的漏洞,不算完全的AC)
如果你真的想完全AC,就上网上搜搜Dancing Links,这个可以省去for t:=1 to 9 do 时的耗时,只用从链表中取出一个数就ok了.
加油AC这道题吧,如果你写程序熟练,最多一个多小时就能AC...
为了防止楼主对我的答案不够满意,附上我的倒着搜的程序代码,加点注释,希望可以帮助你理解.
program sudoku;
type arr=array[1..9]of integer;
var a:array[1..9,1..9]of integer;
xp,yp,zp:array[1..9]of arr;{分别是横行,竖列,9个九宫格的布尔判重数组}
t,k,i,j,m,n,max:longint;
const p:array[1..9,1..9]of integer= {每个格的分值}
((6,6,6,6,6,6,6,6,6),
(6,7,7,7,7,7,7,7,6),
(6,7,8,8,8,8,8,7,6),
(6,7,8,9,9,9,8,7,6),
(6,7,8,9,10,9,8,7,6),
(6,7,8,9,9,9,8,7,6),
(6,7,8,8,8,8,8,7,6),
(6,7,7,7,7,7,7,7,6),
(6,6,6,6,6,6,6,6,6));
q:array[1..9,1..9]of integer= {表示每个格属于的九宫格编号}
((1,1,1,2,2,2,3,3,3),
(1,1,1,2,2,2,3,3,3),
(1,1,1,2,2,2,3,3,3),
(4,4,4,5,5,5,6,6,6),
(4,4,4,5,5,5,6,6,6),
(4,4,4,5,5,5,6,6,6),
(7,7,7,8,8,8,9,9,9),
(7,7,7,8,8,8,9,9,9),
(7,7,7,8,8,8,9,9,9));
procedure init(x,y,i:integer);{把进数独的数做上标记}
var t,k:longint;
begin
xp[x,i]:=1;
yp[y,i]:=1;
zp[q[x,y],i]:=1;
end;
procedure outit(x,y,i:integer);{取消标记}
var t,k:longint;
begin
xp[x,i]:=0;
yp[y,i]:=0;
zp[q[x,y],i]:=0;
end;
procedure sou(x,y,total:integer);{DFS哈...}
var t,k,i:longint;
begin
if (x=0)and(y=9) then
begin
if total>max then max:=total;
exit;
end;
if m>20000000 then {这个是卡时,具体卡多少节点要看评测机速度}
begin
writeln(max);
halt;
end;
if a[x,y]>0 then
begin
t:=x;
k:=y-1;
if y=1 then
begin
dec(t);
k:=9;
end;
inc(m);
sou(t,k,total+a[x,y]*p[x,y]);
end
else
begin
t:=x;
k:=y-1;
if y=1 then
begin
dec(t);
k:=9;
end;
for i:=1 to 9 do
if (xp[x][i]=0)and(yp[y][i]=0)and(zp[q[x,y],i]=0) then
begin
inc(m);
init(x,y,i);
sou(t,k,total+i*p[x,y]);
outit(x,y,i);
end;
end;
end;
begin
for t:=1 to 9 do
begin
for k:=1 to 9 do
begin
read(a[t,k]);
if a[t,k]>0 then init(t,k,a[t,k]);
end;
readln;
end;
sou(9,9,0);{横坐标,纵坐标,当前得分}
if max=0 then max:=-1; {特判}
writeln(max);
end.
如果楼主对我的回答满意,就加点分奖励奖励吧,这个绝对是原创啊...
基本思想:一共9*9=81个格,每个格如果没有数就for t:=1 to 9 do 检查是否可填t,填入、递归,如果搜到了第82层,也就是完成了一个数独,就算一下,更新最大值.搜完后输出最大值就ok了.
不过这个是果断过不了的.
如果你刚刚学DFS,估计你能过6个点也就可以了(一共20个点啊);
如果你比较熟练了,就加些优化,大概可以过15个点(已经很不错了);
如果再加卡时的话,大概最好能过18个点(这是正着搜);
接下来你就知道该干啥了吧——
呵呵...倒着搜哈(也可以随机搜额)...这样大概就可以AC了(但这个果断是利用了数据的漏洞,不算完全的AC)
如果你真的想完全AC,就上网上搜搜Dancing Links,这个可以省去for t:=1 to 9 do 时的耗时,只用从链表中取出一个数就ok了.
加油AC这道题吧,如果你写程序熟练,最多一个多小时就能AC...
为了防止楼主对我的答案不够满意,附上我的倒着搜的程序代码,加点注释,希望可以帮助你理解.
program sudoku;
type arr=array[1..9]of integer;
var a:array[1..9,1..9]of integer;
xp,yp,zp:array[1..9]of arr;{分别是横行,竖列,9个九宫格的布尔判重数组}
t,k,i,j,m,n,max:longint;
const p:array[1..9,1..9]of integer= {每个格的分值}
((6,6,6,6,6,6,6,6,6),
(6,7,7,7,7,7,7,7,6),
(6,7,8,8,8,8,8,7,6),
(6,7,8,9,9,9,8,7,6),
(6,7,8,9,10,9,8,7,6),
(6,7,8,9,9,9,8,7,6),
(6,7,8,8,8,8,8,7,6),
(6,7,7,7,7,7,7,7,6),
(6,6,6,6,6,6,6,6,6));
q:array[1..9,1..9]of integer= {表示每个格属于的九宫格编号}
((1,1,1,2,2,2,3,3,3),
(1,1,1,2,2,2,3,3,3),
(1,1,1,2,2,2,3,3,3),
(4,4,4,5,5,5,6,6,6),
(4,4,4,5,5,5,6,6,6),
(4,4,4,5,5,5,6,6,6),
(7,7,7,8,8,8,9,9,9),
(7,7,7,8,8,8,9,9,9),
(7,7,7,8,8,8,9,9,9));
procedure init(x,y,i:integer);{把进数独的数做上标记}
var t,k:longint;
begin
xp[x,i]:=1;
yp[y,i]:=1;
zp[q[x,y],i]:=1;
end;
procedure outit(x,y,i:integer);{取消标记}
var t,k:longint;
begin
xp[x,i]:=0;
yp[y,i]:=0;
zp[q[x,y],i]:=0;
end;
procedure sou(x,y,total:integer);{DFS哈...}
var t,k,i:longint;
begin
if (x=0)and(y=9) then
begin
if total>max then max:=total;
exit;
end;
if m>20000000 then {这个是卡时,具体卡多少节点要看评测机速度}
begin
writeln(max);
halt;
end;
if a[x,y]>0 then
begin
t:=x;
k:=y-1;
if y=1 then
begin
dec(t);
k:=9;
end;
inc(m);
sou(t,k,total+a[x,y]*p[x,y]);
end
else
begin
t:=x;
k:=y-1;
if y=1 then
begin
dec(t);
k:=9;
end;
for i:=1 to 9 do
if (xp[x][i]=0)and(yp[y][i]=0)and(zp[q[x,y],i]=0) then
begin
inc(m);
init(x,y,i);
sou(t,k,total+i*p[x,y]);
outit(x,y,i);
end;
end;
end;
begin
for t:=1 to 9 do
begin
for k:=1 to 9 do
begin
read(a[t,k]);
if a[t,k]>0 then init(t,k,a[t,k]);
end;
readln;
end;
sou(9,9,0);{横坐标,纵坐标,当前得分}
if max=0 then max:=-1; {特判}
writeln(max);
end.
如果楼主对我的回答满意,就加点分奖励奖励吧,这个绝对是原创啊...
看了noip2009靶形数独讲讲算...的网友还看了以下:
如图,有一块长61cm,宽55cm的铁板,需要从中切割下半径为10cm的圆形零件,想想看,如何才能 2020-05-16 …
如图,p是正三角形ABC内的一点,若将三角形PAB绕点A逆时针旋转到三角形P'AC,则角PAP'等 2020-05-16 …
一道等边三角形的证明题ABC为等边三角形,P为ABC内任意一点,证明PA+PB+PC呃,想了半天。 2020-07-15 …
P是正三角形ABC内的一点,且PA=6,PB=8,PC=10,若将三角形PAC绕点A逆时针旋转后, 2020-07-15 …
如图所示,P是正三角形ABC内一点,且PA=6,PB=8,PC=10如图,P是正三角形ABC内的一 2020-07-31 …
如图,点M是矩形ABCD的边AD的中点,点P是BC边上一动点,PE⊥MC,PF⊥BM,垂足为E、F 2020-08-03 …
(2012•通州区一模)已知四边形ABCD,点E是射线BC上的一个动点(点E不与B、C两点重合), 2020-08-03 …
已知四边形ABCD,点E是射线BC上的一个动点(点E不与B、C两点重合),线段BE的垂直平分线交射 2020-08-03 …
碟形弹簧的力我查机械设计手册,关于碟形弹簧,参数表里面写:当变形量为0.83mm的时候,碟形弹簧的载 2020-12-02 …
已知概率密度函数和概率分布函数,如何产生一个符合概率密度函数图形的时间序列?X为随机序列,概率密度函 2020-12-24 …