zju1942Frog(并查集)

本文介绍了一种解决青蛙跳跃问题的方法,即计算两只青蛙间最小最大跳跃距离的算法。通过连接所有石头之间的边并排序,逐步合并连通块直至两只青蛙处于同一连通块内,此时边的长度即为所需最小最大跳跃距离。
有一只叫做Freddy的青蛙坐在湖中央的一块石头上,突然间他发现另一只青蛙(她的名字是Fiona)坐在另一颗石头上。他想要过去找她,但是因为湖水很脏,到处充满着游客的防晒油,所以他决定用跳的,而不要用游的。
不妙的是Fiona的石头离他的距离超出他所能跳的范围。因此Freddy考虑利用其它的一些石头当作中继站,因此他就可以跳比较小的距离(或许要跳许多次)去找Fiona。
要这样子连续的跳,很明显的Freddy一次能跳的距离必须至少和这一串石头间的距离最大的距离一样。因此,介于石头间的蛙跳距离(frog distance,人类也称之为minmax distance)定义为要从Freddy所在的石头要跳到Fiona所在的石头的路径中,最小必须要跳的距离。

给你Freddy所在的石头、Fiona所在的石头,以及湖中所有其它石头的坐标,你的任务是算出介于Freddy和Fiona所在石头间的蛙跳距离。


此题要求的边是两点间路径的最大边的最小值。将每两个点连边,按边的长度从小到大排序,然后枚举每条边,不断将边的端点所在的连通块合并,知道某一条边使得起点和终点在一个连通块内了,那么这条边的长度便是答案,因为已经不可能存在比他更小的边可以联通起点和终点了。


CODE:

var
  st,ed:array[0..40000] of longint;
  dist:array[0..40000] of real;
  fa,x,y:array[0..200] of longint;
  n,i,j,k,tot,zzb:longint;

  function find(x:longint):longint;
  begin
     if fa[x]=x then exit(x);
     fa[x]:=find(fa[x]);
     exit(fa[x]);
  end;

  procedure qsort(l,r:longint);
  var i,j,tt:longint;
      m,t:real;
  begin
     i:=l; j:=r; m:=dist[(i+j) div 2];
     repeat
       while dist[i]<m do inc(i);
       while dist[j]>m do dec(j);
       if i<=j then
       begin
        t:=dist[i]; dist[i]:=dist[j]; dist[j]:=t;
        tt:=st[i]; st[i]:=st[j]; st[j]:=tt;
        tt:=ed[i]; ed[i]:=ed[j]; ed[j]:=tt;
        inc(i); dec(j);
       end;
     until i>j;
     if (l<j) then qsort(l,j);
     if (i<r) then qsort(i,r);
  end;

  procedure init;
  var i,j,a,b:longint;
  begin
    readln(n); zzb:=0;
    while n<>0 do
    begin
    inc(zzb);
    tot:=0;
    for i:=1 to n do
    readln(x[i],y[i]);
    for i:=1 to n-1 do
     for j:=i+1 to n do
     begin
        inc(tot);
        st[tot]:=i;
        ed[tot]:=j;
        dist[tot]:=sqrt(sqr(x[i]-x[j])+sqr(y[i]-y[j]));
     end;
     qsort(1,tot);
     for i:=1 to n do
      fa[i]:=i;
     for i:=1 to tot do
     begin
        a:=find(st[i]);
        b:=find(ed[i]);
        if a<>b then
         fa[a]:=b;
        if find(1)=find(2) then
        begin
         writeln('Scenario #',zzb);
         writeln('Frog Distance = ',dist[i]:0:3);
         writeln;
         break;
        end;
     end;
     readln(n);
    end;
  end;
begin
 init;
end.


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值