P2976 船舶周围的一个岛屿

实在看不下去了,楼上的题解是个啥ID34354的题解还没有注释…
算了…
盯着看了2个小时,算是看懂了,解释一下吧
顺便给P党一些福音QAQ
为了解释方便,变量名几乎没变QAQ

const z:array[1..4,1..2]of -1..1=((0,1),(1,0),(0,-1),(-1,0));//常量数组
//这个不可以随便定义
{
要→↓←↑的方式定义,不然...
}
var i,j,k,m,n,p,q,x,y,v,o:longint;
    a:array[0..1001,0..1001]of char;
procedure dfs(x,y:longint);//该程序最玄学的部分
var i,c,p,v:longint;
    u:array[1..4]of longint;
begin
  c:=0;
  for i:=1 to 4 do
  if a[x+z[i,1],y+z[i,2]]='A' then//统计出周围的A的个数与方向
  begin
    inc(c);
    u[c]:=i;
  end;
  if(c=2)and
  ((u[1]=1)and(u[2]=3)
  or(u[1]=2)and(u[2]=4)or
  (a[x-z[u[1],1]-z[u[2],1],
     y-z[u[1],2]-z[u[2],2]]='x'))then
  exit;
  {(Y为现在查找的位置)
  当出现
 A 
 Y
 A
 或
 AYA
 这种情况则可能是通道,不可以删去
 还有一种情况
   A
  AY
    x
  这个情况比较特殊,因为不可以从x的外面走,所以Y是通道,不能删去
  }
  if(c>1)then
  begin
    a[x,y]:='A';
    //把当前位置删去
    for i:=1 to 4 do
    begin
      p:=x+z[i,1];
      v:=y+z[i,2];
      if(p>1)and(v>1)and(p<n)and(v<m)and(a[p][v]='.') then
      dfs(p,v);//查找下一个位置
    end;
  end;
end;
function vaild(x,y:longint):boolean;//判断这格可不可以走
begin
  exit((x>0)and(y>0)and(x<n+1)and(y<m+1)and(a[x,y]='.'));
end;
function left(fx:longint):longint;//左转
begin
  if fx=1 then exit(4) else exit(fx-1);
end;
function right(fx:longint):longint;//右转
begin
  if fx=4 then exit(1) else exit(fx+1);
end;
begin
  readln(n,m);
  for i:=1 to n do
  begin
    for j:=1 to m do
    read(a[i,j]);
    readln;
  end;
  for i:=2 to n-1 do
  for j:=2 to m-1 do
  if a[i,j]='.' then
  dfs(i,j);
  {看一下DFS完成后的样例效果
  把没用的.都变成了A
...................
...................
....AAA............
....AAA.x..........
..x.AAA...AAAAA....
....AAAAAAAAAAA....
....AAAAAAAAAAA....
....AAAAAAA...A....
.xx.AAAAAAA.x.A....
....AAAAAAA........
...AAAAAAAAAAAAA...
...................
}
  o:=0;//储存答案
  for i:=1 to n do
  for j:=1 to m do
  if a[i,j]='A' then
  begin
    //可以得出,该最佳路线必然进过最上端的A的上面
    p:=i-1;
    q:=j;
    v:=1;
    repeat//这个可以说是贪心吧...
    {
    为了让改路线尽可能的贴着大陆走
    语文初始方向为→
    所以说要贴着走的话,当可以右转时要右转,不可以则尽可能直走,再不行就只能左转,这样还可以防止直接走回起点(终点)
    就是要绕着这个处理好的岛屿顺时针转一圈
    }
      if(vaild(p+z[right(v),1],q+z[right(v),2]))then//最好右转
      begin
        p:=p+z[right(v),1];
        q:=q+z[right(v),2];
        v:=right(v);
      end
      else
      if(vaild(p+z[v,1],q+z[v,2]))then//尽可能直走
      begin
        p:=p+z[v,1];
        q:=q+z[v,2];
      end
      else
      if(vaild(p+z[left(v),1],q+z[left(v),2]))then//实在不行就左转
      begin
        p:=p+z[left(v),1];
        q:=q+z[left(v),2];
        v:=left(v);
      end;
      inc(o);//每走一步答案+1
    until(p=i-1)and(q=j);//转了一圈就结束了
    write(o);//输出结果
    {(+为走过的路线,F为起点)最后效果就是这样
...................
...+F+++...........
...+AAA+...........
...+AAA+x+++++++...
..x+AAA+++AAAAA+...
...+AAAAAAAAAAA+...
...+AAAAAAAAAAA+...
...+AAAAAAA+++A+...
.xx+AAAAAAA+x+A+...
..++AAAAAAA++++++..
..+AAAAAAAAAAAAA+..
..+++++++++++++++..
    }
    exit;
  end;
end.

只能说,有题解是好事,没有解释怎么办呢…QAQ

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值