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; }