USACO 6.5.3 Betsy's Tour dfs

来源:互联网 发布:java 字符串gbk转utf8 编辑:程序博客网 时间:2024/06/04 23:36

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

优化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: ymwbegi1PROG: betsyLANG: 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.


0 0