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;
}
posted @ 2018-07-04 15:00  Monster_Qi  阅读(35)  评论(0编辑  收藏