bzoj 1050

ANS=MAX/MIN。

先把边按照权值从大到小sort一遍。

按顺序枚举MIN,MAX需要尽量小,所以就是让S和T联通的最大边权最小。

这不就是最小生成树的性质吗?

于是直接Kruskal水过,直到S和T在同一集合就break。

#include<cstdio>
#include<cctype>
#include<algorithm>
using namespace std;
int gcd(int x,int y){return !y? x:gcd(y,x%y);}
int read(){
    char c; while(!isdigit(c=getchar())); int x=c-'0';
    while(isdigit(c=getchar())) x=x*10+c-'0'; return x;
}
struct edge{
    int u,v,c;
}e[5001];
int cmp(edge x,edge y){
    return x.c>y.c;
}
int fa[501];
int find(int x){return x==fa[x]? x:fa[x]=find(fa[x]);}
int main(){
    int n=read(),m=read(),ans1=0,ans2=0;
    for(int i=1;i<=m;i+=1)
        e[i].u=read(),
        e[i].v=read(),
        e[i].c=read();
    sort(e+1,e+m+1,cmp);
    int s=read(),t=read();
    for(int i=1;i<=m;i+=1){
        int pre=0;
        for(int j=1;j<=n;j+=1) fa[j]=j;
        for(int j=i;j>=1;j-=1){
            int x=find(e[j].u),y=find(e[j].v);
            if(x!=y){
                fa[x]=y;
                if(find(s)==find(t)){pre=j; break;}
            }
        }
        if(pre)
        if((!ans1 && !ans2) || ans1*e[i].c>e[pre].c*ans2){
            int k=gcd(e[i].c,e[pre].c);
            ans1=e[pre].c/k;
            ans2=e[i].c/k;
        }
    }
    if(!ans1 && !ans2) printf("IMPOSSIBLE");
    else if(ans1%ans2) printf("%d/%d",ans1,ans2); else printf("%d",ans1/ans2);
    return 0;
}

 

posted @ 2017-10-22 20:15  或是七一  阅读(49)  评论(0编辑  收藏