题目大意
题目链接
有
n
n
n个点
m
m
m条路,第
a
i
a_i
ai路行驶速度必须为
w
i
w_i
wi,现要从点
s
s
s去点
t
t
t,求最快速度和最慢速度的比最小为多少(必要时化成最简分数)。如果无法从点
s
s
s到点
t
t
t,输出IMPOSSIBLE。
解题思路
看到用路线联通两个点,就想到了可以用并查集做。因为要求最小的比为多少,所以我们肯定希望最大速度和最小速度接近,因此我们可以先按速度排一遍序。我们排好序后,最快速度肯定出现在最慢速度的后面,因此我们只需要从第 1 1 1条路枚举到第 m m m条路,再从当前枚举的路线 i i i向后枚举,每遇到一条路就用把它们连接起来,直到点 s s s和点 t t t互通为止,因为已经排好序的原因,当前枚举的路线 i i i的速度就是最慢速度,最后一条使两点连接的路的速度就是最快速度。因为可能会出现多条路通往点 t t t的可能,所以每次找到合法方案就需要和之前找到的最优方案进项对比。(如果把每一条路都连接了还是到不了点 t t t,则输出IMPOSSIBLE)
代码
#include<bits/stdc++.h>
using namespace std;
struct ap{
int x,y,w;
}a[10050];
int n,m,fx,k,fy,p[10050],fast,slow;
double minn=2147483647;
int find(int x)
{
if(p[x]==x) return x;
return p[x]=find(p[x]);
}
void join(int x,int y)
{
p[find(x)]=p[find(y)];
}
bool cmp(ap x,ap y)
{
return x.w<y.w;
}
int main()
{
cin>>n>>m;
for(int i=1;i<=m;i++)
cin>>a[i].x>>a[i].y>>a[i].w;
cin>>fx>>fy;
sort(a+1,a+m+1,cmp);
for(int i=1;i<=m;i++)//枚举起始边
{
for(int j=1;j<=n;j++) p[j]=j;
bool flag=0;
k=i;
while(1)
{
if(k>m) break;//如果找完全程都没有联通
join(a[k].x,a[k].y);
if(find(fx)==find(fy)){//如果连接了则说明到第k条路就能把两点连接
flag=1;
break;
}
k++;
}
if(flag){
if(double(a[k].w)/double(a[i].w)<minn)//比较最优方案
{
minn=double(a[k].w)/double(a[i].w);
fast=a[k].w;
slow=a[i].w;
}
}
}
if(minn!=2147483647)//如果有联通路线
{
if(fast%slow==0) cout<<fast/slow;
else cout<<fast/__gcd(fast,slow)<<"/"<<slow/__gcd(fast,slow);//化简
}
else cout<<"IMPOSSIBLE";
return 0;
}