【Kruskal】舒适的路线
[codevs1001]舒适的路线
Z小镇是一个景色宜人的地方,吸引来自各地的观光客来此旅游观光。
Z小镇附近共有
N(1<N≤500)个景点(编号为1,2,3,…,N),这些景点被M(0<M≤5000)条道路连接着,所有道路都是双向的,两个景点之间可能有多条道路。也许是为了保护该地的旅游资源,Z小镇有个奇怪的规定,就是对于一条给定的公路Ri,任何在该公路上行驶的车辆速度必须为Vi。频繁的改变速度使得游客们很不舒服,因此大家从一个景点前往另一个景点的时候,都希望选择行使过程中最大速度和最小速度的比尽可能小的路线,也就是所谓最舒适的路线。
第一行包含两个正整数,N和M。
接下来的M行每行包含三个正整数:x,y和v(1≤x,y≤N,0 最后一行包含两个正整数s,t,表示想知道从景点s到景点t最大最小速度比最小的路径。s和t不可能相同。
如果景点s到景点t没有路径,输出“IMPOSSIBLE”。否则输出一个数,表示最小的速度比。如果需要,输出一个既约分数。
样例1
4 2
1 2 1
3 4 2
1 4
样例2
3 3
1 2 10
1 2 5
2 3 8
1 3
样例3
3 2
1 2 2
2 3 4
1 3
样例1
IMPOSSIBLE
样例2
5/4
样例3
2
N(1<N≤500)
M(0<M≤5000)
Vi在int范围内
试题分析:本题看似最小生成树解毫无头绪,其实我们只需要确定一个最短边,最长边就被确定出来了
我们进行如下操作:
①枚举一个最短边(当前生成树的)
②枚举一个最长边(当前生成树,可以被以后比他大的边替代的)
1.将最短边与最长边合并
2.如果现在最长边/最短边已经大于ans了,那么枚举比现在的最长边还大的边当最长边是对答案没有意义的事了,可以break
3.如果现在S到T联通,那么就可以直接更新答案(之前的所有ans1都小于ans,现在满足条件了就可以更新)
③除以最大公约数
这类题(最大边和最小边关系的最值操作)都可以用这个架构来解决,如Uva1395这道题,就在此题基础上改一改就好了
代码:
#include<iostream> #include<cstring> #include<cstdio> #include<algorithm> using namespace std; inline int read(){ int x=0,f=1;char c=getchar(); for(;!isdigit(c);c=getchar()) if(c=='-') f=-1; for(;isdigit(c);c=getchar()) x=x*10+c-'0'; return x*f; } int N,M; struct data{ int x,y,v; }e[5001]; bool cmp(data a,data b){ return a.v<b.v; } int fa[5001]; void init(){ for(int i=1;i<=N;i++) fa[i]=i; return ; } int find(int x){ if(x!=fa[x]) return fa[x]=find(fa[x]); return x; } int ans1,ans2; int gcd(int a,int b){if(b==0) return a;return gcd(b,a%b);} int main(){ N=read(),M=read(); for(int i=1;i<=M;i++){ e[i].x=read(),e[i].y=read(); e[i].v=read(); } ans1=ans2=-1; int S=read(),T=read(); sort(e+1,e+M+1,cmp); for(int i=1;i<=M;i++){ init(); for(int j=i;j<=M;j++){ int u=find(e[j].x),v=find(e[j].y);fa[v]=u; if(ans1!=-1&&((double)((double)e[j].v/(double)e[i].v))>=((double)((double)ans2/(double)ans1))) break; if(find(S)==find(T)) {ans1=e[i].v;ans2=e[j].v;break;} } if(ans1==-1){puts("IMPOSSIBLE");return 0;} } int k=gcd(ans1,ans2); ans1/=k;ans2/=k; if(ans1==1) printf("%d\n",ans2); else printf("%d/%d",ans2,ans1); }