USACO 3.3 Camelot亚瑟王的宫殿(最短路)

这居然是IOI 98的题目耶,我居然写出来了,想想就有点小激动呢(我绝对不会说出来我看了题解)!

题目大意就是在一个n*m的矩阵中有一个国王和若干个骑士。国王每一步可以往任意方向走一格(包括斜着),骑士每一步走的是日子型(跟象棋里的马一样,没下过的自己面壁去)。当骑士和国王相遇时骑士可以带着国王走,每次只算一步。现在要求所有骑士和国王在任意一点会和最少需要走的步数。

题解:先用bfs求出每个点之间的距离dis[i,j,k,l]然后就开始枚举接国王。s[i,j,1]表示所有骑士走到点(i,j)的最短路径,s[i,j,2]表示某个骑士接王后到点(i,j)的最短路径,然后就开始三重循环。考虑到骑士比王走得快,所以应让王尽量少走,但不排除有些骑士不能到王那里(要是换成我果断把那骑士炒了),所以要枚举王往方圆两格中走。然后计算最小值就好了。但还要考虑到王自己走到集合点的情况。

大概就这样了……最慢的点0.43ms,还是蛮快的。

本人语文成绩比较捉急,大家凑合着看吧(感觉自己都不太看得懂)。

下面附代码(本人是P狗,请勿嘲笑)

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

var
  n,m,y,kingx,kingy,a1,i,j,k,w,ans:longint;
  x:char;
  a:array[1..780,1..2] of longint;
  dis:array[1..30,1..26,1..30,1..26] of longint;
  v:array[1..30,1..26] of boolean;
  state:array[1..10000,1..3] of longint;
  s:array[1..30,1..26,1..2] of longint;

procedure bfs(x,y:longint);
var
  head,tail,i,p,q:longint;
begin
  fillchar(v,sizeof(v),true);
  v[x,y]:=false;
  dis[x,y,x,y]:=0;
  head:=0;
  tail:=1;
  state[1,1]:=x;
  state[1,2]:=y;
  state[1,3]:=0;
  repeat
    inc(head);
    for i:=1 to 8 do
    begin
      p:=state[head,1]+dx[i];
      q:=state[head,2]+dy[i];
      if (p<1)or(p>n)or(q<1)or(q>m) then continue;
      if not v[p,q] then continue;
      v[p,q]:=false;
      dis[x,y,p,q]:=state[head,3]+1;
      inc(tail);
      state[tail,1]:=p;
      state[tail,2]:=q;
      state[tail,3]:=state[head,3]+1;
    end;
  until head>=tail;
end;

function max(x,y:longint):longint;
begin
  if x>y then exit(x)
         else exit(y);
end;

function min(x,y:longint):longint;
begin
  if x<y then exit(x)
         else exit(y);
end;

function work(z,x,y:longint):longint;
var
  s,i,j:longint;
begin
  work:=maxlongint;
  for i:=max(kingx-2,1) to min(kingx+2,n) do
    for j:=max(kingy-2,1) to min(kingy+2,m) do
    begin
      s:=dis[a[z,1],a[z,2],i,j]+dis[i,j,x,y]+1;
      if (i=kingx)and(j=kingy) then dec(s);
      if (i=kingx-2)or(i=kingx+2)or(j=kingy-2)or(j=kingy+2) then inc(s);
      if s<work then work:=s;
    end;
end;

begin
  readln(n,m);
  readln(x,y);
  kingx:=y;
  kingy:=ord(x)-ord('A')+1;
  while not eof do
  begin
    read(x,y);
    inc(a1);
    a[a1,1]:=y;
    a[a1,2]:=ord(x)-ord('A')+1;
    if eoln
      then readln
      else read(x);
  end;
  {for i:=1 to 4 do
  begin
    readln(x,y);
    inc(a1);
    a[a1,1]:=y;
    a[a1,2]:=ord(x)-ord('A')+1;
  end;}
  fillchar(dis,sizeof(dis),$7f div 3);
  for i:=1 to n do
    for j:=1 to m do
      bfs(i,j);
  for i:=1 to n do
    for j:=1 to m do
    begin
      for k:=1 to a1 do
        s[i,j,1]:=s[i,j,1]+dis[a[k,1],a[k,2],i,j];
      s[i,j,2]:=maxlongint;
    end;
  ans:=maxlongint;
  for i:=1 to n do
    for j:=1 to m do
    begin
      for k:=1 to a1 do
      begin
        w:=work(k,i,j);
        if s[i,j,1]-dis[a[k,1],a[k,2],i,j]+w<s[i,j,2] then
          s[i,j,2]:=s[i,j,1]-dis[a[k,1],a[k,2],i,j]+w;
      end;
      if s[i,j,1]+dis[kingx,kingy,i,j]<ans then
        ans:=s[i,j,1]+dis[kingx,kingy,i,j];
      if s[i,j,2]<ans then ans:=s[i,j,2];
    end;
  if a1=0 then ans:=0;
  writeln(ans);
end.



你可能感兴趣的:(USACO 3.3 Camelot亚瑟王的宫殿(最短路))