1. 程式人生 > 實用技巧 >BZOJ-1050 [HAOI2006]旅行comf(並查集+Kruskal演算法)

BZOJ-1050 [HAOI2006]旅行comf(並查集+Kruskal演算法)

題目描述

  給一個無向圖,\(n(n\leq 500)\) 個點,\(m(m\leq 5000)\) 條邊,每條邊有一個權值 \(v_i(v_i\leq 30000)\)。給兩個頂點\(S\)\(T\) ,求一條路徑,使得 \(S\rightarrow T\) 路徑上最大邊和最小邊的比值最小。如果 \(S\)\(T\) 之間沒有路徑,輸出 IMPOSSIBLE,否則輸出這個比值。

分析

  列舉最小邊權,再把比它邊權大的邊依次加入到圖中,直到 \(S\)\(T\) 連通,記錄最大邊和最小邊的比值,列舉更新答案。

程式碼

#include<bits/stdc++.h>
using namespace std;
const double INF=0x3f3f3f3f;
const int N=510,M=5010;
int n,m,fa[N];
struct Edge
{
    int u,v,w;
}edge[M<<1];
bool cmp(Edge A,Edge B)
{
    return A.w<B.w;
}
int get(int x)
{
    if(fa[x]==x)
        return x;
    return fa[x]=get(fa[x]);
}
int main()
{
    cin>>n>>m;
    for(int i=1;i<=n;i++)
        fa[i]=i;
    for(int i=1;i<=m;i++)
    {
        scanf("%d %d %d",&edge[i].u,&edge[i].v,&edge[i].w);
        int fx=get(edge[i].u),fy=get(edge[i].v);
        if(fx!=fy)
            fa[fx]=fy;
    }
    int S,T;
    cin>>S>>T;
    if(get(S)!=get(T))
    {
        puts("IMPOSSIBLE");
        return 0;
    }
    sort(edge+1,edge+1+m,cmp);
    int fz,fm;
    double ans=INF;
    for(int i=1;i<=m;i++)
    {
        int pos;
        bool flag=false;
        for(int j=1;j<=n;j++)
            fa[j]=j;
        for(int j=i;j<=m;j++)
        {
            int fx=get(edge[j].u),fy=get(edge[j].v);
            if(fx!=fy)
                fa[fx]=fy;
            if(get(S)==get(T))
            {
                flag=true;
                pos=j;
                break;
            }
        }
        if(flag)
        {
            double temp=1.0*edge[pos].w/edge[i].w;
            if(temp<ans)
            {
                int gcd=__gcd(edge[pos].w,edge[i].w);
                fz=edge[pos].w/gcd;
                fm=edge[i].w/gcd;
                ans=temp;
            }
        }
    }
    if(fm==1)
        printf("%d\n",fz);
    else
        printf("%d/%d\n",fz,fm);
    return 0;
}