无线通讯网 纪中3078 最小生成树

Description

国防部计划用无线网络连接若干个边防哨所。2种不同的通讯技术用来搭建无线网络:每个边防哨所都要配备无线电收发器;有一些哨所还可以增配卫星电话。

任意两个配备了一条卫星电话线路的哨所均可以通话,无论它们相距多远。而只通过无线电收发器通话的哨所之间的距离不能超过D,这是受收发器的功率限制。收发器的功率越高,通话距离D会更远,但同时价格也更贵。

收发器需要统一购买和安装,所以全部哨所只能选择安装一种型号的收发器。换句话说,每一对哨所之间的通话距离都是同一个D。

你的任务是确定收发器必须的最小通话距离D,使得每一对哨所之间至少有一条通话路径(直接的或者间接的)。

Input

第1行:2个整数S(1 <= S <= 100)和P(S < P <= 500),S表示可安装的卫星电话的线路数,P表示边防哨所的数量。

接下来P行,每行描述一个哨所的平面坐标(x,y),以km为单位,整数,0<=x,y<=10,000

Output

第1行:1个实数D,表示无线电收发器的最小传输距离。精确到小数点后2位。

分析

因为是图论专题,所以想一想则会发现,图的生成树具有把图连通的功能,
而最小生成树的最大边是所有生成树中最大边最小的。
这个性质还可以加强为:若把生成树的N-1条边按权值排序,则最小生成树的每条边都不大于另一棵生成树。 
这样,就可以先用KRUSKAL算法求出一棵最小生成树的N-1条边(加并查集优化)。
然后找到第N-1-S条边的长度,即是题目所求的D值。

代码

const
  maxn=1000;
  maxe=500000;

type
  arr=record
    x,y:longint;
    w:real;
end;

var
  dis:array[1..maxe] of arr;
  edge:array[1..maxe] of arr;
  x,y:array[1..maxn] of longint;
  father:array[1..maxn] of longint;
  n,m,nm:longint;
  ans:real;

procedure add(x,y:longint;w:real);
begin
  m:=m+1;
  edge[m].x:=x;
  edge[m].y:=y;
  edge[m].w:=w;
end;

procedure init;
var
  i,j,k:longint;
  distance:real;
begin
  readln(nm,n);
  for i:=1 to n do
    readln(x[i],y[i]);
  for i:=1 to n do
    begin
      for j:=i+1 to n do
        begin
          distance:=sqrt(sqr(x[i]-x[j])+sqr(y[i]-y[j]));
          add(i,j,distance);
        end;
    end;
end;

procedure qsort(l,r:longint);
var
  i,j,k:longint;
  temp:arr;
  mid:real;
begin
  if l>=r then exit;
  i:=l; j:=r;
  mid:=edge[(l+r) div 2].w;
  repeat
    while edge[i].wdo i:=i+1;
    while edge[j].w>mid do j:=j-1;
    if i<=j then
      begin
        temp:=edge[i]; edge[i]:=edge[j]; edge[j]:=temp;
        i:=i+1; j:=j-1;
      end;
  until i>j;
  qsort(l,j);
  qsort(i,r);
end;

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

procedure union(x,y:longint);
var
  i,j:longint;
begin
  i:=find(x); j:=find(y);
  father[i]:=j;
end;

procedure main;
var
  i,j,k:longint;
begin
  init;
  qsort(1,m);
  for i:=1 to n do
    father[i]:=i;
  j:=0;
  i:=1;
  while j1 do
    begin
      with edge[i] do
        begin
          if find(x)<>find(y)
            then
              begin
                j:=j+1;
                dis[j]:=edge[i];
                union(x,y);
              end;
        end;
      i:=i+1;
    end;
  nm:=nm-1;
  if nm>=n
    then write(0.00:0:2)
    else write(dis[j-nm].w:0:2);
end;

begin
  main;
end.

你可能感兴趣的:(并查集,最小生成树)