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

原文地址:https://www.cnblogs.com/Loi-Brilliant/p/9757908.html

时间: 2024-07-31 01:32:24

P2502 [HAOI2006]旅行 - 最小生成树【最小比值生成树(雾】的相关文章

luogu题解P2502[HAOI2006]旅行--最小生成树变式

题目链接 https://www.luogu.org/problemnew/show/P2502 分析 一个很\(naive\)的做法是从\(s\)到\(t\)双向BFS这当然会TLE 这时我就有个想法就是二分套二分边下标来求得一个比值,同时排序后从小到大枚举每一条边作为最小值,同时再枚举每一条边,如果边权之比小于比值就连起来用并查集维护连通性,可是这个时间复杂度\(O(m^2 log^2m \ \alpha(n))\)过不去QAQ 然后想为什么不直接枚举每条边作为最小值,同时搞一颗以这条边为最

P2502 [HAOI2006]旅行 最小生成树

思路:枚举边集,最小生成树 提交:1次 题解:(如思路) #include<cstdio> #include<iostream> #include<algorithm> #define R register int using namespace std; #define ull unsigned long long #define ll long long #define pause (for(R i=1;i<=10000000000;++i)) #define

(最小生成树/最小瓶颈生成树) 2017武汉现场赛 - Wifi Relay

题意: n个无线AP,有xy坐标属性,现在n个无线AP要桥接在一起不能断开连接,现在要求无线AP无线网络的覆盖半径最小是多少 分析: 看起来是像是最小生成树,这里是是求生成树中最长的边最短,就是最小瓶颈生成树. 可以证明最小瓶颈生成树就是最小生成树,详细看刘汝佳<算法入门经典训练指南>343页. 当时现场的时候,想试试最小生成树了,结果以为n方复杂度过不去,就没写,现在想起来,真是坑哦. 这题n有10000,所以不能直接建邻接矩阵,而是采用动态计算距离就行了. 比赛结束了随便一写就A了...

luogu P2502 [HAOI2006]旅行

传送门 边数只有5000,可以考虑\(O(m^2)\)算法,即把所有边按边权升序排序,然后依次枚举每条边\(i\),从这条边开始依次加边,加到起点和终点在一个连通块为止.这个过程可以用并查集维护.那么以\(i\)这条边为最小边的合法路径,最大值最小的边就是最后加进去的边,这时用这两个边权更新答案即可 可以加一些形如当前比值比答案更差就退出的剪枝 #include<bits/stdc++.h> #define LL long long #define il inline #define re r

bzoj 1050: [HAOI2006]旅行comf(最小生成树+并查集)

1050: [HAOI2006]旅行comf Time Limit: 10 Sec  Memory Limit: 162 MB Submit: 2405  Solved: 1282 [Submit][Status][Discuss] Description 给你一个无向图,N(N<=500)个顶点, M(M<=5000)条边,每条边有一个权值Vi(Vi<30000).给你两个顶点S和T ,求一条路径,使得路径上最大边和最小边的比值最小.如果S和T之间没有路径,输出"IMPOSS

【最小瓶颈生成树】【最小生成树】【kruscal】bzoj1083 [SCOI2005]繁忙的都市

本意是求最小瓶颈生成树,但是我们可以证明:最小生成树也是最小瓶颈生成树(其实我不会).数据范围很小,暴力kruscal即可. 1 #include<cstdio> 2 #include<algorithm> 3 using namespace std; 4 struct Edge{int u,v,w;void Read(){scanf("%d%d%d",&u,&v,&w);}}edges[10001]; 5 bool operator &

1050: [HAOI2006]旅行comf

1050: [HAOI2006]旅行comf Time Limit: 10 Sec  Memory Limit: 162 MBSubmit: 1495  Solved: 737[Submit][Status] Description 给你一个无向图,N(N<=500)个顶点, M(M<=5000)条边,每条边有一个权值Vi(Vi<30000).给你两个顶点S和T,求一条路径,使得路径上最大边和最小边的比值最小.如果S和T之间没有路径,输出”IMPOSSIBLE”,否则输出这个比值,如果需

[HAOI2006]旅行comf

1050: [HAOI2006]旅行comf Time Limit: 10 Sec  Memory Limit: 162 MB Submit: 3450  Solved: 1919 [Submit][Status][Discuss] Description 给你一个无向图,N(N<=500)个顶点, M(M<=5000)条边,每条边有一个权值Vi(Vi<30000).给你两个顶点S和T,求 一条路径,使得路径上最大边和最小边的比值最小.如果S和T之间没有路径,输出"IMPOSS

POJ2728 最小比率生成树/0-1分数规划/二分/迭代(迭代不会)

用01分数规划 + prime + 二分 竟然2950MS惊险的过了QAQ 前提是在TLE了好几次下过的 = = 题目意思:有n个村庄,村庄在不同坐标和海拔,现在要对所有村庄供水,只要两个村庄之间有一条路即可,建造水管距离为坐标之间的欧几里德距离,费用为海拔之差,现在要求方案使得费用与距离的比值最小,很显然,这个题目是要求一棵最优比率生成树. 解题思路: 对答案进行二分,当把代进去的答案拿来算最小生成树的时候,一旦总路径长度为0,就是需要的答案. 0-1规划是啥? 概念有带权图G, 对于图中每条