codevs1001

题目地址:http://codevs.cn/problem/1001/

分析:

简单的并查集

把边权按从小到大的顺序排好序枚举每一条边,把这条边的边权作为ans_max,接下来从这条边开始按顺序(从大到小)枚举每一条比它小的边,并且把这条边的两端点划分到一个联通块中,并且判断起点和终点是否在同一个联通块中,如果在同一个联通块中,那么当前枚举到的边的权值就是ans_min,然后更新当前最优解即可。

原理:枚举、贪心,因为我们要求ans_max与ans_min的最小比值,ans_max与ans_min越接近肯定是越好的。所以我们枚举ans_max,这样就可以把ans_max当成常数,那么ans_min的值一定是越大越好(当然,它不可能大过ans_max),所以我们从当前枚举到的边开始,每次加一条略小的边进入,当S与T第一次联通时,ans_min的值是最大的,那么就能保证他们的比值是当前ans_max下最小的。


代码:

type

  node=record

    f,t:longint;

  end;

  node1=record

    a,b,v:longint;

  end;

  node2=record

    v1,v2:longint;

    v:real;

  end;

var

  max:real;

  n,m,i,a,b,v,j,l,r,maxv1,maxv2,xb:longint;

  f:array[0..501] of node;

  g:array[0..5001] of node1;


procedure print(x,y:longint);

var

  a,b,r,t:longint;


begin

  if x<y then begin t:=x;x:=y;y:=t end;

  a:=x;b:=y;

  r:=a mod b;

  while r<>0 do

    begin

      a:=b;

      b:=r;

      r:=a mod b;

    end;

  if y div b=1 then writeln(x div b)

  else writeln(x div b,'/',y div b);

  halt;

end;


procedure sort(l,r: longint);

      var

         i,j,x: longint;

y: node1;

      begin

         i:=l;

         j:=r;

         x:=g[(l+r) div 2].v;

         repeat

           while g[i].v>x do

            inc(i);

           while x>g[j].v do

            dec(j);

           if not(i>j) then

             begin

                y:=g[i];

                g[i]:=g[j];

                g[j]:=y;

                inc(i);

                j:=j-1;

             end;

         until i>j;

         if l<j then

           sort(l,j);

         if i<r then

           sort(i,r);

      end;


function find(x:longint):longint;

begin

  if f[x].f=x then exit(x)

  else begin

    f[x].f:=find(f[x].f);

    exit(f[x].f);

  end;

end;


procedure union(x,y:longint);

var

  a,b:longint;


begin

  a:=find(x);

  b:=find(y);

  if a=b then exit;

  if f[a].t<f[b].t

  then begin f[a].f:=b;inc(f[b].t,f[a].t); end

  else begin f[b].f:=a;inc(f[a].t,f[b].t); end;

end;


function check(x,y:longint):boolean;

begin

  if find(x)=find(y)then exit(true)

                    else exit(false);

end;


begin

  readln(n,m);

  for i:=1 to n do begin f[i].f:=i;f[i].t:=1; end;

  for i:=1 to m do

    begin

      read(a,b,v);

      union(a,b);

      g[i].a:=a;g[i].b:=b;g[i].v:=v;

    end;

  readln(l,r);

  if not check(l,r) then begin writeln('IMPOSSIBLE');halt end;

  sort(1,m);

  max:=maxlongint;

  for i:=1 to m do

    begin

      for j:=1 to n do begin f[j].f:=j;f[j].t:=1;end;

      for j:=i to m do

        begin

          union(g[j].a,g[j].b);

          if check(l,r) then break;

        end;

      if not check(l,r) then continue;

      if (g[i].v/g[j].v<max) and (i<>j)

      then begin

        max:=g[i].v/g[j].v;

        maxv1:=g[i].v;maxv2:=g[j].v;

      end;

    end;

  if maxv2=0 then print(1,1)

  else print(maxv1,maxv2);

end.


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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值