BZOJ 1050: [HAOI2006]旅行comf
Time Limit: 10 Sec Memory Limit: 162 MB
Submit: 4011 Solved: 2249
[Submit][Status][Discuss]
Description
给你一个无向图,N(N<=500)个顶点, M(M<=5000)条边,每条边有一个权值Vi(Vi<30000)。给你两个顶点S和T,求
一条路径,使得路径上最大边和最小边的比值最小。如果S和T之间没有路径,输出”IMPOSSIBLE”,否则输出这个
比值,如果需要,表示成一个既约分数。 备注: 两个顶点之间可能有多条路径。
Input
第一行包含两个正整数,N和M。下来的M行每行包含三个正整数:x,y和v。表示景点x到景点y之间有一条双向公路
,车辆必须以速度v在该公路上行驶。最后一行包含两个正整数s,t,表示想知道从景点s到景点t最大最小速度比
最小的路径。s和t不可能相同。
1
解题思路
模仿最小生成树里克鲁斯卡尔做法,先将边权从小到大排序,然后枚举之后的边,直到将S到T联通,然后更新答案即可。
代码
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
using namespace std;
const int MAXN = 5005;
inline int rd(){
int x=0,f=1;char ch=getchar();
while(!isdigit(ch)) {if(ch=='-') f=-1;ch=getchar();}
while(isdigit(ch)) {x=(x<<1)+(x<<3)+ch-48;ch=getchar();}
return x*f;
}
struct Edge{
int to,val,fr;
}edge[MAXN<<1];
int n,head[MAXN],m;
int mx=1<<30,mn=1;
int fa[MAXN],S,T;
inline bool cmp(Edge A,Edge B){
return A.val<B.val;
}
inline int find(int x){
if(x==fa[x]) return x;
return fa[x]=find(fa[x]);
}
int main(){
n=rd();m=rd();
for(register int i=1;i<=m;i++)
edge[i].fr=rd(),edge[i].to=rd(),edge[i].val=rd();
S=rd(),T=rd();
sort(edge+1,edge+1+m,cmp);
for(register int i=1;i<=m;i++){
int p=-1;
for(register int j=1;j<=n;j++) fa[j]=j;
for(register int j=i;j<=m;j++){
int u=find(edge[j].fr),v=find(edge[j].to);
if(u!=v) fa[u]=v;
if(find(S)==find(T)) {p=j;break;}
}
if(p==-1) continue;
if((double)mx/(double)mn>(double)edge[p].val/double(edge[i].val))
mx=edge[p].val,mn=edge[i].val;
}
if(mx==(1<<30)) {puts("IMPOSSIBLE");return 0;}
int g=__gcd(mn,mx);
mn/=g,mx/=g;
if(mn==1) printf("%d",mx);
else printf("%d/%d",mx,mn);
return 0;
}