P2864 树林

坎坷的做题旅程
先用bfs码了一个计算绕森林最小路程
找到最上点,最右点,最下点,最左点。利用凸包特性去写。

const z:array[1..8,1..2]of -1..1=((0,1),(1,1),(1,0),(1,-1),(0,-1),(-1,-1),(-1,0),(-1,1));
var i,j,k:longint;
    m,n:longint;
    x,y:array[0..10000]of longint;
    fax,fay:array[0..100,0..100]of longint;
    a,b:array[0..100,0..100]of boolean;
    fx,fy,h,t:longint;
    x1,y1:longint;
    ch:char;
    limx,limy:array[1..4]of longint;
    can:array[1..4,1..8]of boolean;
    now:array[0..10000]of longint;
    ans:longint;
function pd(x,y,x1,y1:longint):boolean;
var i:longint;
begin
  for i:=1 to 8 do
  if i mod 2=1 then
  if (x+z[i,1]=x1) and (y+z[i,2]=y1) then exit(true);
  exit(false);
end; 
begin
  for i:=1 to 3 do//每种可以走的方向
  can[1,i]:=true;
  for i:=3 to 5 do
  can[2,i]:=true;
  for i:=5 to 7 do
  can[3,i]:=true;
  for i:=7 to 8 do
  can[4,i]:=true;
  can[4,1]:=true;
  readln(m,n);
  for i:=1 to m do
  begin
    for j:=1 to n do
    begin
      read(ch);
      if ch='X' then
      begin
        a[i][j]:=true;
        if limx[1]=0 then
        begin
          limx[1]:=i;
          limy[1]:=j;
        end;
        limx[3]:=i;
        limy[3]:=j;
        if(j>limy[2])or(limx[2]=0)
        then
        begin
          limx[2]:=i;
          limy[2]:=j;
        end;
        if(j<limy[4])or(limx[4]=0)
        then
        begin
          limx[4]:=i;
          limy[4]:=j;
        end;    
      end
      else b[i,j]:=true;
      if ch='*' then
      begin
        fx:=i;
        fy:=j;
      end;
    end;
    readln;
  end;
  h:=1;
  t:=1;
  x[1]:=limx[1]-1;
  y[1]:=limy[1];
  now[1]:=1;
  repeat
    if (now[t]=4) and (x[t]+1=limx[1]) and (y[t]=limy[1]) then//到终点
    begin
      break;
    end;
    if (now[t]=1) and (x[t]=limx[2]) and (y[t]-1=limy[2]) then//改变
    begin
      now[t]:=2;
    end;
    if (now[t]=2) and (x[t]-1=limx[3]) and (y[t]=limy[3]) then//改变
    begin
      now[t]:=3;
    end;
    if (now[t]=3) and (x[t]=limx[4]) and (y[t]+1=limy[4]) then//改变
    begin
      now[t]:=4;
    end;
    for i:=1 to 8 do//八个方向查找
    if can[now[t],i] then
    if b[x[t]+z[i,1],y[t]+z[i,2]] then
    begin
      inc(h);
      b[x[t]+z[i,1],y[t]+z[i,2]]:=false;
      x[h]:=x[t]+z[i,1];
      y[h]:=y[t]+z[i,2];
      fax[x[h],y[h]]:=x[t];//记录father
      fay[x[h],y[h]]:=y[t];
      now[h]:=now[t];
    end;
    inc(t);
  until h<t;
  for i:=1 to m do
  for j:=1 to n do
  a[i,j]:=true;
  x1:=x[t];
  y1:=y[t];
  x[0]:=x1;
  y[0]:=y1;
  x1:=fax[x[0],y[0]];
  y1:=fay[x[0],y[0]];
  while (x1<>limx[1]-1)or(y1<>limy[1]) do//倒退找路径
  begin
    a[x1,y1]:=false;
    x[0]:=x1;
    y[0]:=y1;
    x1:=fax[x[0],y[0]];
    y1:=fay[x[0],y[0]];
    inc(ans);
  end;
  a[limx[1]-1,limy[1]]:=false;
  h:=1;
  t:=1;
  x[1]:=fx;
  y[1]:=fy;
  now[1]:=0;
  for i:=1 to m do
  for j:=1 to n do
  b[i,j]:=true;
  b[fx,fy]:=false;
  repeat
    if not a[x[t],y[t]] then//找到解
    begin
      write(ans+now[t]+2);//凑
      exit;//30分
    end;
    for i:=1 to 8 do
    if b[x[t]+z[i,1],y[t]+z[i,2]] then
    begin
      inc(h);
      x[h]:=x[t]+z[i,1];
      y[h]:=y[t]+z[i,2];
      b[x[h],y[h]]:=false;
      now[h]:=now[t]+1;
    end;
    inc(t);
  until t>h;
end.

又改进了一下

const z:array[1..8,1..2]of -1..1=((0,1),(1,1),(1,0),(1,-1),(0,-1),(-1,-1),(-1,0),(-1,1));
var i,j,k:longint;
    m,n:longint;
    x,y:array[0..10000]of longint;
    fax,fay:array[0..100,0..100]of longint;
    min:array[0..100,0..100]of longint;
    a,b,c,d:array[0..100,0..100]of boolean;
    fx,fy,h,t:longint;
    x1,y1:longint;
    ch:char;
    limx,limy:longint;
    can:array[1..8]of boolean;
    now:array[0..10000]of longint;
    ans:longint;
    sum:longint;
    x2,y2:longint;
procedure dfs(x,y:longint);
var i:longint;
begin
  if not c[x,y] then exit;
  c[x,y]:=false;
  a[x,y]:=true;
  for i:=1 to 8 do
  if min[x+z[i,1],y+z[i,2]]=min[x,y]-1 then
  dfs(x+z[i,1],y+z[i,2]);
end;
begin
  readln(m,n);
  for i:=1 to m do
  begin
    for j:=1 to n do
    begin
      read(ch);
      if ch='*' then
      begin
        fx:=i;
        fy:=j;
      end;
      if ch='X' then
      begin
        if limx=0 then
        begin
          limx:=i-1;
          limy:=j;
        end;
      end
      else b[i,j]:=true;
    end;
    readln;
  end;
  c:=b;
  d:=b;
  x[1]:=limx;
  y[1]:=limy;
  sum:=0;
  x2:=limx;
  y2:=limy;
  while x2>0 do
  begin
    x2:=x2-1;
    inc(sum);
    min[x2,y2]:=sum;
    b[x2,y2]:=false;
  end;
  h:=1;
  t:=1;
  now[1]:=0;
  can[1]:=true;
  can[2]:=true;
  can[8]:=true;
  for i:=1 to 8 do
  if can[i] then
  if b[x[t]+z[i,1],y[t]+z[i,2]] then
  begin
    b[x[t]+z[i,1],y[t]+z[i,2]]:=false;
    inc(h);
    x[h]:=x[t]+z[i,1];
    y[h]:=y[t]+z[i,2];
    min[x[h],y[h]]:=now[t]+1;
    now[h]:=now[t]+1;
    fax[x[h],y[h]]:=limx;
    fay[x[h],y[h]]:=limy;
  end;
  inc(t);
  repeat
    if (x[t]=limx) and (y[t]=limy) then
    break;
    for i:=1 to 8 do
    if b[x[t]+z[i,1],y[t]+z[i,2]] and
    (((x[t]+z[i,1])<>fax[x[t],y[t]])
    or ((y[t]+z[i,2])<>fay[x[t],y[t]])) then
    begin
      inc(h);
      x[h]:=x[t]+z[i,1];
      y[h]:=y[t]+z[i,2];
      now[h]:=now[t]+1;
      min[x[h],y[h]]:=now[h];
      b[x[h],y[h]]:=false;
    end;
    inc(t);
  until t>h;
  dfs(limx,limy);
  x[1]:=fx;
  y[1]:=fy;
  t:=1;
  h:=1;
  now[1]:=0;
  repeat
    if a[x[t],y[t]] then
    begin
      write(now[t]+min[limx,limy]);
      exit;
    end;
    for i:=1 to 8 do
    if d[x[t]+z[i,1],y[t]+z[i,2]] then
    begin
      inc(h);
      x[h]:=x[t]+z[i,1];
      y[h]:=y[t]+z[i,2];
      now[h]:=now[t]+1;
      d[x[h],y[h]]:=false;
    end;
    inc(t);
  until h<t;
end.
因为路径不止一条,这个可以把所有都找出来

这时才发现题目看错了QAQ
不过,还好,很快就AC了

const z:array[1..8,1..2]of -1..1=((0,1),(1,1),(1,0),(1,-1),(0,-1),(-1,-1),(-1,0),(-1,1));
var i,j,k:longint;
    m,n:longint;
    x,y:array[0..10000]of longint;
    fax,fay:array[0..100,0..100]of longint;
    min:array[0..100,0..100]of longint;
    a,b,c,d:array[0..100,0..100]of boolean;
    fx,fy,h,t:longint;
    x1,y1:longint;
    ch:char;
    limx,limy:longint;
    can:array[1..8]of boolean;
    now:array[0..10000]of longint;
    ans:longint;
    sum:longint;
    x2,y2:longint;//很多变量没用,只是懒得删,顺便见证一下坎坷的做题旅途
function small(m,n:longint):longint;//min用掉了
begin
  if m>n then exit(n) else exit(m); 
end;
begin
  readln(m,n);
  for i:=1 to m do
  begin
    for j:=1 to n do
    begin
      read(ch);
      if ch='*' then//起点
      begin
        fx:=i;
        fy:=j;
      end;
      if ch='X' then
      begin
        if limx=0 then
        begin
          limx:=i-1;
          limy:=j;
        end;
        min[i,j]:=9999999;//永远也到不了
      end
      else b[i,j]:=true;
    end;
    readln;
  end;
  c:=b;
  d:=b;
  x2:=limx;
  y2:=limy;
  sum:=0;
  b[limx,limy]:=false;
  while x2>0 do//把环打破,一边的加另一边便是最优解
  begin
    x2:=x2-1;
    inc(sum);
    min[x2,y2]:=sum;
    b[x2,y2]:=false;
  end;
  h:=1;//队列
  t:=1;
  now[1]:=0;
  x[1]:=fx;
  y[1]:=fy;
  repeat
    for i:=1 to 8 do
    if b[x[t]+z[i,1],y[t]+z[i,2]] then
    begin
      inc(h);
      x[h]:=x[t]+z[i,1];
      y[h]:=y[t]+z[i,2];
      now[h]:=now[t]+1;
      min[x[h],y[h]]:=now[h];
      b[x[h],y[h]]:=false;
    end;
    inc(t);
  until t>h;
  write(small(min[limx,limy-1],min[limx+1,limy-1])+small(min[limx,limy+1]{左边最优解},min[limx+1,limy+1]){同理,右边最优解}+2{其中漏算的两个点});//最优解必然在这些位置
end.

呀AC了
做题之路一路坎坷

猜你喜欢

转载自blog.csdn.net/sxy__orz/article/details/86100894
p
今日推荐