并查集 HAOI 2006 旅行

版权声明:未经本蒟蒻同意,请勿转载本蒻博客 https://blog.csdn.net/wddwjlss/article/details/82229487

题意:一个图,边有边权,给定起点 s , t ,求 s t 的路径上最大边权与最小边权的最小比值。

m <= 5000 意味着可以跑大概小于 O ( m 2 ) 的算法,所以我们将边根据边权从小到大排序后,枚举每一条边作为最小边,枚举大于等于这条边的所有边,通过并查集进行合并,当s和t联通时求出此时的最大边权与最小边权的比值,不断更新答案即可。

#include<bits/stdc++.h>
using namespace std;
struct node
{
    int x,y,d;
}e[1001000];
int n,m,s,t,f[1001000],maxn,minn;
double ep=99999;
int find(int x)
{
    if(x==f[x])
        return x;
    else
    {
        f[x]=find(f[x]);
        return f[x];
    } 
}
bool cmp(node n1,node n2)
{
    return n1.d<n2.d;
}
int gcd(int a,int b)
{
    if(b==0)
        return a;
    else
        return gcd(b,a%b);
}
int main()
{
    cin>>n>>m;
    for(int i=1;i<=m;++i)
        scanf("%d%d%d",&e[i].x,&e[i].y,&e[i].d);
    cin>>s>>t;
    sort(e+1,e+m+1,cmp);
    for(int i=1;i<=m;++i)
    {
        bool flag=0;
        for(int j=1;j<=n;++j)
            f[j]=j;
        int u,v;
        u=v=e[i].d;
        for(int j=i;j<=m;++j)
        {
            int fx=find(e[j].x);
            int fy=find(e[j].y);
            if(fx!=fy)
            {
                f[fx]=fy;
                v=e[j].d;
            } 
            if(find(s)==find(t))
            {
                flag=1;
                break;
            }
        }
        if(double(v)/double(u)<ep&&flag)
        {
            ep=double(v)/double(u);
            maxn=v;
            minn=u;
        }
    }
    if(!minn)
    {
        cout<<"IMPOSSIBLE";
        return 0;
    }   
    if(ep!=int(ep))
    {
        int c1=gcd(maxn,minn);
        maxn/=c1;
        minn/=c1;
        cout<<maxn<<"/"<<minn;
        return 0;
    }
    cout<<ep;
    return 0;
}

猜你喜欢

转载自blog.csdn.net/wddwjlss/article/details/82229487