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

题目链接

https://www.luogu.org/problemnew/show/P2502

分析

一个很\(naive\)的做法是从\(s\)到\(t\)双向BFS这当然会TLE

这时我就有个想法就是二分套二分边下标来求得一个比值,同时排序后从小到大枚举每一条边作为最小值,同时再枚举每一条边,如果边权之比小于比值就连起来用并查集维护连通性,可是这个时间复杂度\(O(m^2 log^2m \ \alpha(n))\)过不去QAQ

然后想为什么不直接枚举每条边作为最小值,同时搞一颗以这条边为最小值且联通s,t的最小生成树呢,因为边是排序好的,这样答案是单调的,且正确性是显然的时间复杂度\(O(m^2)\).

代码

#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cstdlib>
#include <algorithm>
#include <cctype>
#include <cmath>
#define ll long long
#define ri register int
using std::sort;
using std::min;
using std::max;
using std::swap;
template <class T>inline void read(T &x){
    x=0;int ne=0;char c;
    while(!isdigit(c=getchar()))ne=c==‘-‘;
    x=c-48;
    while(isdigit(c=getchar()))x=(x<<3)+(x<<1)+c-48;
    x=ne?-x:x;return ;
}
const int maxm=5005;
const int maxn=505;
const int inf=0x7fffffff;
struct Edge{
    int x,y,dis;
    bool operator <(const Edge &b)const{
        return dis<b.dis;
    }
}edge[maxm];
int num_edge=0;
int n,m,s,t;
int fa[maxn];
int get(int x){return fa[x]==x?fa[x]:(fa[x]=get(fa[x]));}
int gcd(int a,int b){
    return b?gcd(b,a%b):a;
}
int main(){
    int x,y,v,xx,yy;
    bool flag=0;
    read(n),read(m);
    for(ri i=1;i<=m;i++){
        read(x),read(y),read(v);
        edge[i].x=x,edge[i].y=y,edge[i].dis=v;
    }
    read(s),read(t);
    sort(edge+1,edge+1+m);
    int mx,cnt=0;
    double mi=inf;
    int fz,fm;
    for(ri i=1;i<=m;i++){
        mx=-inf,flag=0;
        for(ri j=1;j<=n;j++)fa[j]=j;
        for(ri j=i;j<=m;j++){
            x=edge[j].x,y=edge[j].y,v=edge[j].dis;
            xx=get(x),yy=get(y);
            if(xx==yy)continue;
            fa[xx]=yy;
            mx=max(mx,v);
            if(get(s)==get(t)){
                flag=1;break;
            }//if(cnt==n-1)break;
        }
        if(i==1&&get(s)!=get(t)){
            puts("IMPOSSIBLE");
            return 0;
        }
        else if(flag){
            double tmp=(double)mx/edge[i].dis;
            //printf("%d %d %lf\n",mx,edge[i].dis,tmp);
            if(tmp<mi){
                flag=1;
                mi=tmp;
                fm=edge[i].dis,fz=mx;
            }
        }
    }
    int GCD=gcd(fz,fm);
    fm=fm/GCD,fz=fz/GCD;
    if(fm==1)printf("%d\n",fz);
    else printf("%d/%d\n",fz,fm);
    return 0;
}

原文地址:https://www.cnblogs.com/Rye-Catcher/p/9560671.html

时间: 2024-07-30 09:03:01

luogu题解P2502[HAOI2006]旅行--最小生成树变式的相关文章

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第一次连通时

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

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

[HAOI2006]旅行 题解(kruskal)

[HAOI2006]旅行 Description Z小镇是一个景色宜人的地方,吸引来自各地的观光客来此旅游观光.Z小镇附近共有N个景点(编号为1,2,3,-,N),这些景点被M条道路连接着,所有道路都是双向的,两个景点之间可能有多条道路.也许是为了保护该地的旅游资源,Z小镇有个奇怪的规定,就是对于一条给定的公路Ri,任何在该公路上行驶的车辆速度必须为Vi.速度变化太快使得游客们很不舒服,因此从一个景点前往另一个景点的时候,大家都希望选择行使过程中最大速度和最小速度的比尽可能小的路线,也就是所谓最

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”,否则输出这个比值,如果需

C#报表查询区域变式存储内容条件

双击调用存储的变式条件

[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

【原创】洛谷 LUOGU P3366 【模板】最小生成树

P3366 [模板]最小生成树 题目描述 如题,给出一个无向图,求出最小生成树,如果该图不连通,则输出orz 输入输出格式 输入格式: 第一行包含两个整数N.M,表示该图共有N个结点和M条无向边.(N<=5000,M<=200000) 接下来M行每行包含三个整数Xi.Yi.Zi,表示有一条长度为Zi的无向边连接结点Xi.Yi 输出格式: 输出包含一个数,即最小生成树的各边的长度之和:如果该图不连通则输出orz 输入输出样例 输入样例#1: 4 5 1 2 2 1 3 2 1 4 3 2 3 4