旅行 纪中2547 并查集+枚举

Description

  Z 小镇是一个景色宜人的地方,吸引来自各地的观光客来此旅游观光。Z 小镇附近共有N 个景点(编号为1,2,3,…,N),这些景点被M 条道路连接着,所有道路都是双向的,两个景点之间可能有多条道路。也许是为了保护该地的旅游资源,Z 小镇有个奇怪的规定,就是对于一条给定的公路Ri,任何在该公路上行驶的车辆速度必须为Vi。
  速度变化太快使得游客们很不舒服,因此从一个景点前往另一个景点的时候,大家都希望选择行使过程中最大速度和最小速度的比尽可能小的路线,也就是所谓最舒适的路线。

Input

  第一行包含两个正整数,N 和M。
  接下来的M 行每行包含三个正整数:x,y 和v。表示景点x 到景点y 之间有一条双向公路,车辆必须以速度v 在该公路上行驶。
最后一行包含两个正整数s,t,表示想知道从景点s 到景点t 最大最小速度比最小的路径。s 和t 不可能相同。

Output

  如果景点s 到景点t 没有路径,输出“IMPOSSIBLE”。否则输出一个数,表示最小的速度比。如果需要,输出一个既约分数。

数据范围

对于100%的数据,1 < N≤500,1≤x,y≤N,0<M<5000 

分析

因为数据范围比较小,m*m不会爆,所以我们可以枚举最大最小的边。
先按边权从小到大排序,枚举最小边
然后把其他边从小到大加入,把这些边连接的点放入一个集合(并差集)
每加入一条边,就判断s和t是否在一个集合。是的话就是一种可行解。

代码

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

var
  a:array[1..50000] of arr;
  ls:array[1..5000] of longint;
  f:array[1..5000] of longint;
  s,t:longint;
  num:longint;
  ans:real;
  n,m:longint;
  head,tail:longint;
  i,j,k,z:longint;

function find(v:longint):longint;
begin
  if f[v]=v
    then exit(v)
    else
      begin
        f[v]:=find(f[v]);
        find:=f[v];
      end;
end;

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

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

procedure c(x,y:longint);
var
  i,j,k:longint;
begin
  i:=x; j:=y;
  while j<>0 do
    begin
      k:=i mod j;
      i:=j;
      j:=k;
    end;
  x:=x div i;
  y:=y div i;
  if x mod y=0 then write(x div y)
               else write(x,'/',y);
end;

procedure add(x,y,w:longint);
begin
  num:=num+1;
  a[num].x:=x;
  a[num].y:=y;
  a[num].w:=w;
  a[num].next:=ls[x];
  ls[x]:=num;
end;

begin
  readln(n,m);
  for i:=1 to m do
    begin
      readln(j,k,z);
      add(j,k,z);
    end;
  read(s,t);
  qsort(1,num);
  ans:=maxlongint;
  head:=0; tail:=0;
  for i:=1 to num do
    begin
      for j:=1 to n do
        f[j]:=j;
      for j:=i to num+1 do
        begin
          if find(s)=find(t) then break;
          if j>num then break;
          union(a[j].x,a[j].y);
        end;
      j:=j-1;
      if (a[j].w/a[i].w<ans) and (find(s)=find(t))
        then
          begin
            ans:=a[j].w/a[i].w;
            head:=a[j].w;
            tail:=a[i].w;
          end;
    end;
  if (head=0) and (tail=0)
    then write('IMPOSSIBLE')
    else c(head,tail);
end.

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值