这道题一眼看过去,应该是最小生成树没错了,我们可以暴力的枚举一下选哪些边,期望得分40~50
正解是什么呢?我们将边按照边权排序,因为我们要在保证联通的条件下,使得costmax/costmin最小,所以我们要让最小边尽量大的情况下,使得最大边尽量小,如何实现呢?我们发现,因为边权数组已经排好序,所以权值是递增的,所以我们可以选择一些小边权的边不选,看是否还能连通,这样就可以实现在最小边扩大的同时,缩小比值
(这次的代码函数较多,为了更清晰,我开了好多函数,不要喷我的码风,自认为还是比较好看的)
代码
//By AcerMo
#include<cmath>
#include<queue>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
const int M=5500;
int up,down;
int n,fa[M],siz[M],m;
double ans=3005000.0;
struct edge
{
int fr,to,cost;
}priq[M<<2];
inline int find(int x)
{
if (x!=fa[x]) return fa[x]=find(fa[x]);
return x;
}
inline int gcd(int a,int b)
{
if (!b) return a;
return gcd(b,a%b);
}
inline int read()
{
int x=0;char ch=getchar();
while (ch>'9'||ch<'0') ch=getchar();
while (ch>='0'&&ch<='9') x=x*10+ch-'0',ch=getchar();
return x;
}
inline void unionn(int a,int b)
{
if (siz[a]<siz[b]) siz[b]+=siz[a],fa[a]=b;
else siz[a]+=siz[b],fa[b]=a;
return ;
}
inline bool cmp(edge a,edge b){return a.cost<b.cost;}
inline void constt()
{
for (int i=1;i<=n;i++) fa[i]=i,siz[i]=1;
return ;
}
inline void jud(int i,int k)
{
double now=(double)priq[i].cost/priq[k].cost;
if (ans>now) ans=now,up=priq[i].cost,down=priq[k].cost;
return ;
}
int main()
{
n=read();m=read();constt();
for (int i=1;i<=m;i++)
{
priq[i].fr=read();priq[i].to=read();priq[i].cost=read();
int r1=find(priq[i].fr),r2=find(priq[i].to);
if (r1!=r2) unionn(r1,r2);
}
int st=read(),ed=read();
if (find(st)!=find(ed)) return puts("IMPOSSIBLE"),0;
sort(priq+1,priq+m+1,cmp);
for (int i=1;i<=m;i++)
{
bool flag=0;int e;constt();
for (int k=i;k<=m;k++)
{
int r1=find(priq[k].fr);
int r2=find(priq[k].to);
if (r1!=r2) unionn(r1,r2);
if (find(st)==find(ed)) {e=k;flag=1;break;}
}
if (flag) jud(e,i);
}
int d=gcd(up,down);
if (d!=down) printf("%d/%d",up/d,down/d);
else cout<<up/d;
return 0;
}