寒假填坑五十道省选题——第五道
[HAOI2006]旅行
题目描述
Z小镇是一个景色宜人的地方,吸引来自各地的观光客来此旅游观光。Z小镇附近共有N个景点(编号为1,2,3,…,N),这些景点被M条道路连接着,所有道路都是双向的,两个景点之间可能有多条道路。也许是为了保护该地的旅游资源,Z小镇有个奇怪的规定,就是对于一条给定的公路Ri,任何在该公路上行驶的车辆速度必须为Vi。速度变化太快使得游客们很不舒服,因此从一个景点前往另一个景点的时候,大家都希望选择行使过程中最大速度和最小速度的比尽可能小的路线,也就是所谓最舒适的路线。
输入输出格式
输入格式:
第一行包含两个正整数,N和M。
接下来的M行每行包含三个正整数:x,y和v。表示景点x到景点y之间有一条双向公路,车辆必须以速度v在该公路上行驶。
最后一行包含两个正整数s,t,表示想知道从景点s到景点t最大最小速度比最小的路径。s和t不可能相同。
输出格式:
如果景点s到景点t没有路径,输出“IMPOSSIBLE”。否则输出一个数,表示最小的速度比。如果需要,输出一个既约分数。
输入输出样例
4 2 1 2 1 3 4 2 1 4
IMPOSSIBLE
3 3 1 2 10 1 2 5 2 3 8 1 3
5/4
3 2 1 2 2 2 3 4 1 3
2
说明
【数据范围】
1<N≤500
1≤x,y≤N,0<v<30000,x≠y
0<M≤5000
第一眼看这个题目发现有些熟悉,才发现是教练在我刚接触信息三四个月时就考过的qwq,当时怎么可能会做嘛orz。
不过那个时候就听懂了题解,这道题根本不用去跑什么最短路什么的,直接一个克鲁斯卡尔+队列就好了,把边从小到大排,然后暴力每一条边为出发点,不断向右边找,直到s==t,这样就能求出比值最小的边了。
//It's made by Epiphyllum 2018/2/10
#include<cstdio> #include<cstring> #include<cmath> #include<iostream> #include<algorithm> #define ll long long using namespace std; int s,t,n,m,fa[50001],ans1,ans2; struct node{ int vi,x,y; }ch[500001]; int read() { int x=0,w=1;char ch=getchar(); while(ch>'9'||ch<'0'){if(ch=='-')w=-1;ch=getchar();} while(ch>='0'&&ch<='9')x=x*10+ch-'0',ch=getchar(); return x*w; } bool cmp(node a,node b) { return a.vi<b.vi; } int find(int x) { if (fa[x]==x) return x; return fa[x]=find(fa[x]); } int gcd(int x,int y) { if (y>x) return gcd(y,x); if (!y) return x; return gcd(y,x%y); } int main() { n=read();m=read(); for(int i=1;i<=m;i++) { ch[i].x=read();ch[i].y=read();ch[i].vi=read(); } s=read();t=read(); sort(ch+1,ch+m+1,cmp); for(int i=1;i<=m;i++) { for(int j=1;j<=n;j++)fa[j]=j; int j; for(j=i;j<=m;j++) { int fx,fy; fx=find(ch[j].x);fy=find(ch[j].y); if(fx==fy)continue; fa[fx]=fy; if(find(s)==find(t))break; } if ((i==1)&&(find(s)!=find(t))) { printf("IMPOSSIBLE\n"); return 0; } if(find(s)!=find(t))break; if(ans1*ch[i].vi>=ans2*ch[j].vi) ans1=ch[j].vi,ans2=ch[i].vi; } int x=gcd(ans1,ans2); if (x==ans2) printf("%d\n",ans1/ans2); else printf("%d/%d\n",ans1/x,ans2/x); return 0; }