题意:一个n个顶点,m条边的无向图,每条边有一个权值vi,给出两个顶点S和T,找出一条S到T的路径使最大边与最小边的比最小。如果S到T没有路径输出:"IMPOSSIBLE" 否则输出最简比值
对于 impossible /是否合法判断 :并查集维护连通性,判断S和T是否在一个集合里
重点考虑要求:最大边与最小边的比最小,那么一定是 让最大边尽量小的同时让最小边尽量大
我们尝试按照一定顺序去枚举S到T之间所有合法路径的最大值和最小值的组合,ans=min(maxn/minn)
我们借鉴kruscal的贪心方法和加边方法
那么,我们可以枚举最小边,判断以这条边为最小边是否有合法路径,如果有合法路径的话找到它对应的最大值
由于我们要时刻保持原则:让最大边尽量小的同时让最小边尽量大
所以我们在枚举最小边后,在找它对应的最大边时要使最大边尽量小,即从恰好不小于最小边的边从小到大加入边,如果s和t在一个集合里就break,最后加入的边就是最大边
那么我们找到了一条合法路径和一条尽量小的最大边,但是我们枚举的这条最小边并不能保证最小边尽量大
怎么办?0.0
倒着再来一遍,从恰好不大于最大边的边从大到小加入边,如果s和t在同一集合里就break,最后加入的边就是该最大边所对应的最小边
此时我们满足了我们的贪心原则:让最大边尽量小的同时让最小边尽量大
判断是否更新答案
================我是理想与现实的分界线_(:з」∠)_================
所以我们的总体思想和方法为:
1、原则:让最大边尽量小的同时让最小边尽量大
2、方法:借鉴kruscal
3、并查集维护连通性
4、先把所有边按边权从小到大排序,枚举最小边判断是否能够成合法的路径,
如果可以找到合法路径,找到最大边并以最大边倒着来一遍找到其对应的最小边判断是否更新答案;
如果不可以找到合法路径直接break掉
(因为[i,m]区间的所有边都无法构成合法路径那么[i+1,m]、[i+2,m] ....区间的所有边也无法构成合法路径)
type
rec=record
a,b,len:longint;
end;
var
n,m,s,t :longint;
maxn,minn :longint;
tmax,tmin :longint;
i :longint;
l :array[0..5010] of rec;
f :array[0..510] of longint;
function get_father(x:longint):Longint;
begin
if x=f[x] then exit(x);
f[x]:=get_Father(f[x]);
exit(F[x]);
end;
function gcd(a,b:longint):longint;
begin
if b=0 then exit(a) else exit(gcd(b,a mod b));
end;
procedure print;
var
tt:longint;
begin
tt:=gcd(maxn,minn);
maxn:=maxn div tt;
minn:=minn div tt;
if (minn=1) then writeln(maxn) else writeln(maxn,'/',minn);
end;
procedure sort(ll,rr:longint);
var
i,j:longint;
x:longint;
y:rec;
begin
i:=ll;j:=rr;
x:=l[(ll+rr)>>1].len;
while (i<=j) do
begin
while (l[i].len<x) do inc(i);
while (l[j].len>x) do dec(j);
if (i<=j) then
begin
y:=l[i];l[i]:=l[j];l[j]:=y;
inc(i);dec(j);
end;
end;
if (i<rr) then sort(i,rr);
if (j>ll) then sort(ll,j);
end;
procedure work(x:longint);
var
ta,tb,tp:longint;
i:longint;
begin
for i:=1 to n do f[i]:=i;
for i:=x to m do
begin
if get_father(s)=get_father(t) then break;
ta:=get_father(l[i].a);
tb:=get_father(l[i].b);
if(ta<>tb) then
begin
tmax:=l[i].len;
tp:=i;
f[tb]:=ta;
end;
end;
if get_father(s)<>get_father(t) then exit;
//
for i:=1 to n do f[i]:=i;
for i:=tp downto 1 do
begin
if get_father(s)=get_father(t) then break;
ta:=get_father(l[i].a);
tb:=get_father(l[i].b);
if (ta<>tb) then
begin
tmin:=l[i].len;
f[tb]:=ta;
end;
end;
end;
begin
read(n,m);
for i:=1 to m do read(l[i].a,l[i].b,l[i].len);
read(s,t);
sort(1,m);
maxn:=maxlongint;minn:=1;
for i:=1 to m do
begin
work(i);
if get_father(s)=get_father(t) then
begin
if tmax/tmin<maxn/minn then
begin
maxn:=tmax;
minn:=tmin;
end;
end else break;
end;
if i=1 then writeln('IMPOSSIBLE') else print;
end.
——by Eirlys