回家_纪中1445_bfs+二分

Description

  Alice住在森林里,森林可以看作是N*M的网格,森林里有怪兽,用‘.’表示空地,‘+’表示怪兽,‘V’表示Alice现在的位置,‘J’表示Alice的家。
  Alice可以从当前单元格向上下左右相邻单元格移动,有怪兽的地方也可以走,只不过比较危险,有怪兽的单元格对其他单元格会产生一定的危险系数,假设怪兽位置为(A,B),它对某单元格(R,C)的危险系数为:|R-A|+|C-B|,危险系数越小越危险,每个单元格的危险系数是所有怪兽对它产生的系数的最小值。
  Alice请你帮她找一条最佳路径回家,即使得路径上经过单元格的最小的危险系数最大。

Input

  输入第一行包含两个整数N和M(1<=N,M<=500),表示森林的大小。
  接下来N行每行包含M个字符:‘.’,‘+’,‘V’,‘J’。
  输入只包含一个‘V’和‘J’,而且至少有一个‘+’。

Output

  输出最佳路径中最小的危险系数。

题解

  这种题目A了才有成就感呀
  
  对于每个怪兽,我们做一次bfs求出每个点的危险系数,然后二分可能的最小危险系数值,代进bfs判断是否可行
  
   交了很多次发现原来是万恶的ansistring在捣鬼,默默吐槽然后就过了
  
   还有就是要判断起点是否大于我们二分的最小值,这点很坑
  
   优化:经过哲♂学地判断我们发现最大值不会超过50 (别问我为什么)

code

type
  state=record
    x,y:longint;
  end;
const
  dx:array[1..4]of integer=(-1,1,0,0);
  dy:array[1..4]of integer=(0,0,-1,1);
var
  n,m:longint;
  map:array[0..501,0..501]of longint;
  f:array[0..501,0..501]of boolean;
  s:array[1..251000]of state;
  st,ed:state;
function bfs(w:longint):boolean;
var
  i,x,y,head,tail:longint;
begin
  if map[st.x,st.y]<w then exit(false);
  fillchar(s,sizeof(s),0);
  fillchar(f,sizeof(f),false);
  bfs:=false;
  head:=0;
  tail:=1;
  s[1].x:=st.x;
  s[1].y:=st.y;
  repeat
    inc(head);
    if (s[head].x=ed.x)and(s[head].y=ed.y) then exit(true);
    for i:=1 to 4 do
    begin
      x:=s[head].x+dx[i];
      y:=s[head].y+dy[i];
      if (not f[x,y])and(map[x,y]>=w)and(x>0)and(x<=n)and(y>0)and(y<=m) then
      begin
        inc(tail);
        f[x,y]:=true;
        s[tail].x:=x;
        s[tail].y:=y;
      end;
    end;
  until head>=tail;
end;
procedure main;
var
  l,r,mid,ans:Longint;
  b:boolean;
begin
  l:=0;
  r:=50;
  ans:=0;
  while l<=r do
  begin
    mid:=(l+r)shr 1;
    b:=bfs(mid);
    if b then
    begin
      if mid>ans then ans:=mid;
      l:=mid+1;
    end
    else
    r:=mid-1;
  end;
  writeln(ans);
end;
procedure init;
var
  i,j,head,tail,x,y,z:longint;
  sr:ansistring;
begin
  fillchar(s,sizeof(s),0);
  fillchar(map,sizeof(map),$7f div 2);
  tail:=0;
  head:=0;
  readln(n,m);
  for i:=1 to n do
  begin
    readln(sr);
    for j:=1 to m do
    begin
      case sr[j] of
        'J':
        begin
          ed.x:=i;
          ed.y:=j;
        end;
        'V':
        begin
          st.x:=i;
          st.y:=j;
        end;
        '+':
        begin
          inc(tail);
          s[tail].x:=i;
          s[tail].y:=j;
          map[i,j]:=0;
        end;
      end;
    end;
  end;
  repeat
    inc(head);
    for i:=1 to 4 do
    begin
      x:=s[head].x+dx[i];
      y:=s[head].y+dy[i];
      z:=map[s[head].x,s[head].y]+1;
      if (map[x,y]>z)and(x>0)and(x<=n)and(y>0)and(y<=m) then
      begin
        inc(tail);
        s[tail].x:=x;
        s[tail].y:=y;
        map[x,y]:=map[s[head].x,s[head].y]+1;
      end;
    end;
  until head>=tail;
end;
begin
  init;
  main;
end.

转载于:https://www.cnblogs.com/olahiuj/p/5781247.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值