USACO 6.5.3 Betsy's Tour dfs

这题数据这么小显然是搜索,但朴素的没法过,所以要想办法剪枝。

优化1

不走死胡同!所谓死胡同,就是走进去以后就再也无法走出来的点。

一种简单的想法是:"任意时刻,必须保证和当前所在位置不相邻的未经点至少有两个相邻的未经点"。基于这种想法,可以采取这样的优化:

  1. 当前点周围的点D,如果只有一个与D相邻的未经点,则点D为必经点。
  2. 显然,如果当前点周围有两个或两个以上的符合上述条件的必经点,则无论走哪个必经点都会造成一个死胡同,需要剪枝。
  3. 如果当前点周围只有一个必经点,则一定要走到这个点。
  4. 如果该点周围没有必经点,则需要枚举周围每一个点。

该优化的力度很大,可以在0.2秒内解决N=6,但N=7仍然需要2秒左右的时间

[编辑]优化2

不要形成孤立的区域!如果行走过程中把路一分为二,那么肯定有一部分再也走不到了,需要剪枝。

形成孤立的区域的情况很多,如果使用Floodfill找连通块,代价会很大,反而会更慢。我只考虑了一种最容易出现特殊情况,即:

  1. 当前点左右都是已经点(包括边缘),而上下都是未经点
  2. 当前点上下都是已经点(包括边缘),而左右都是未经点

这样就会形成孤立的区域,只要将出现这种情况的状态都剪掉即可。

加上优化2,N=7也能在0.3s解决了。

代码:

{
ID: ymwbegi1
PROG: betsy
LANG: PASCAL
} 

const
  dx:array[1..4] of longint=(0,1,0,-1);
  dy:array[1..4] of longint=(1,0,-1,0);

var
  ans,n,i:longint;
  v:array[0..8,0..8] of boolean;

function find(x,y:longint):longint;
var
  i,p,q:longint;
begin
  find:=0;
  for i:=1 to 4 do
  begin
    p:=x+dx[i];
    q:=y+dy[i];
    if (p<1)or(p>n)or(q<1)or(q>n) then continue;
    if v[p,q] then inc(find);
  end;
end;

procedure dfs(x,y,s:longint);
var
  i,u,p,q:longint;
begin
  inc(s);
  if (x=n)and(y=1) then
  begin
    if s=n*n then inc(ans);
    exit;
  end;
  u:=0;
  if (v[x+1,y])and(v[x-1,y])and(v[x,y+1]=false)and(v[x,y-1]=false) then exit;
  if (v[x,y+1])and(v[x,y-1])and(v[x+1,y]=false)and(v[x-1,y]=false) then exit;
  for i:=1 to 4 do
  begin
    p:=x+dx[i];
    q:=y+dy[i];
    if (p<1)or(p>n)or(q<1)or(q>n) then continue;
    if v[p,q]=false then continue;
    if (find(p,q)=1)and((p<>n)or(q<>1)) then
    begin
      if u>0 then exit;
      u:=i;
    end;
  end;
  if u>0
    then begin
           p:=x+dx[u];
           q:=y+dy[u];
           v[p,q]:=false;
           dfs(p,q,s);
           v[p,q]:=true;
         end
    else for i:=1 to 4 do
         begin
           p:=x+dx[i];
           q:=y+dy[i];
           if (p<1)or(p>n)or(q<1)or(q>n) then continue;
           if v[p,q]=false then continue;
           v[p,q]:=false;
           dfs(p,q,s);
           v[p,q]:=true;
         end;
end;

begin
  assign(input,'betsy.in');
  assign(output,'betsy.out');
  reset(input);
  rewrite(output);
  readln(n);
  fillchar(v,sizeof(v),true);
  for i:=1 to n do
  begin
    v[0,i]:=false;
    v[n+1,i]:=false;
    v[i,0]:=false;
    v[i,n+1]:=false;
  end;
  v[1,1]:=false;
  dfs(1,1,0);
  writeln(ans);
  close(input);
  close(output);
end.


你可能感兴趣的:(USACO 6.5.3 Betsy's Tour dfs)