NOIP 2009 提高组 靶形数独

来源:互联网 发布:会计电算化实务软件 编辑:程序博客网 时间:2024/05/21 22:56

这里写图片描述
这里写图片描述
这里写图片描述
这里写图片描述
这里写图片描述
这里写图片描述

题解:
这题就是一个搜索,
用一个数组记录[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.
原创粉丝点击