P2502 [HAOI2006]旅行 - 最小生成树【最小比值生成树(雾】

P2502 [HAOI2006]旅行

Sol:

  • 暴力
    枚举所有从S到T的路径,然后用maxw/minw更新答案。
    时间复杂度:\(O(玄学)\)
  • 正解
    观察到边数\(m\leq5000\)
    考虑由直接求maxw和minw -> 枚举minw求maxw
    由于从S到T的路径上的最大值最小的边一定在最小生成树上(最小生成树的瓶颈路性质),所以我们可以将边从小到大排序,每次枚举边\(e_i\),并将剩下的\(e_i,e_{i+1}\dots e_m\)建最小生成树,当边\(e_k\)使S和T第一次连通时,用\(e_k/e_i\)更新答案。

    AC Code:

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
using namespace std;
int read(){
    int x=0,f=1;char ch=' ';
    while(ch>'9'||ch<'0') {if(ch=='-') f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9') {x=(x<<3)+(x<<1)+ch-'0';ch=getchar();}
    return x*f;
}
const int N = 500 + 100,M = 5000 + 100;
int n,m,s,t;
struct node{
    int u,v,w;
    bool operator < (const node& a)const{
        return w<a.w;
    }
}e[M];
int gcd(int a,int b){
    return !b?a:gcd(b,a%b);
}
int fa[N];
int find(int x){
    return fa[x]==x?x:fa[x]=find(fa[x]);
}
double tmpmax;
int ansmax,ansmin;
bool ok;
void kruskal(int l){
    for(int i=1;i<=n;i++) fa[i]=i;
    for(int i=l;i<=m;i++){
        int u=e[i].u,v=e[i].v,w=e[i].w;
        int p=find(u),q=find(v);
        if(p!=q){
            fa[p]=q;
        }
        if(find(s)==find(t)){
            tmpmax=w;
            ok=0;
            break;
        }
    }
    return ;
}
int main(){
//  freopen("data.in","r",stdin);
//  freopen("sol.out","w",stdout);
    n=read();m=read();
    for(int i=1;i<=n;i++) fa[i]=i;
    int tot=0;
    for(int i=1;i<=m;i++){
        int u,v,w;u=read();v=read();w=read();
        e[i]=(node){u,v,w};
        fa[find(u)]=find(v);
    }
    sort(e+1,e+m+1);
    s=read();t=read();
    if(find(s)!=find(t)){
        printf("IMPOSSIBLE");return 0;
    }
    double ans=10000000.0;
    for(int i=1;i<=m;i++){
        ok=1;
        kruskal(i);
        if(ok) continue;//S与T不连通
        double res=tmpmax/e[i].w;
        if(res<ans){
            ansmin=e[i].w;
            ansmax=floor(tmpmax);
            ans=min(ans,res);
        }
    }
    if(ansmax%ansmin==0){
        printf("%d",ansmax/ansmin);
    }
    else{
        int GCD=gcd(ansmin,ansmax);
        ansmin/=GCD,ansmax/=GCD;
        printf("%d/%d",ansmax,ansmin);
    }
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/Loi-Brilliant/p/9757908.html
今日推荐