1. 程式人生 > >洛谷P2502[HAOI2006]旅行

洛谷P2502[HAOI2006]旅行

題目:

Z小鎮是一個景色宜人的地方,吸引來自各地的觀光客來此旅遊觀光。Z小鎮附近共有N個景點(編號為1,2,3,…,N),這些景點被M條道路連線著,所有道路都是雙向的,兩個景點之間可能有多條道路。也許是為了保護該地的旅遊資源,Z小鎮有個奇怪的規定,就是對於一條給定的公路Ri,任何在該公路上行駛的車輛速度必須為Vi。速度變化太快使得遊客們很不舒服,因此從一個景點前往另一個景點的時候,大家都希望選擇行使過程中最大速度和最小速度的比儘可能小的路線,也就是所謂最舒適的路線。

題目連結:旅行

輸入:

第一行包含兩個正整數,N和M。

接下來的M行每行包含三個正整數:x,y和v。表示景點x到景點y之間有一條雙向公路,車輛必須以速度v在該公路上行駛。

最後一行包含兩個正整數s,t,表示想知道從景點s到景點t最大最小速度比最小的路徑。s和t不可能相同。

輸出:

如果景點s到景點t沒有路徑,輸出“IMPOSSIBLE”。否則輸出一個數,表示最小的速度比。如果需要,輸出一個最簡分數。

分析:

並查集維護最小生成樹,用kruskal跑,也算是並查集運用了吧(……)

對於這種求比值的題,我們可以列舉一個定值(最大值或者最小值),另外一個值跑最小生成樹,根據最小生成樹的性質可以得到當s和t連通的第一時刻加進去的那條邊和前面定下來的值的比值就是這個定值的情況下的最優解
然後打個擂臺找最小就可以了,用double存一下ans,然後最後輸出的時候分子分母都要除以gcd
注意特判是整數的情況
沒了


程式碼:

#include<bits/stdc++.h>
#define N 500+5
#define M 5000+5 
#define INF 1<<21
using namespace std;
int fa[N];
int n,m,s,t,l,r;
double ans=INF;
inline int read(){
    int cnt=0,f=1;char c;
    c=getchar();
    while(!isdigit(c)){
        if(c=='-')f=-f;
        c=getchar();
    }
    while(isdigit(c)){
        cnt=cnt*10+c-'0';
        c=getchar();
    }
    return cnt*f;
}
int find_father(int x){
    if(fa[x]==x)return x;
    return fa[x]=find_father(fa[x]);
}

int gcd(int a,int b){
    if(!b)return a;
    else return gcd(b,a%b);
}
struct node{
    int x;
    int y;
    int v;
}edge[M];
bool cmp(node a,node b){
    return a.v<b.v;
}
int main(){
    n=read();m=read();
    for(register int i=1;i<=n;i++)fa[i]=i;
    for(register int i=1;i<=m;i++){
        edge[i].x=read();
        edge[i].y=read();
        edge[i].v=read();
        int x=find_father(edge[i].x);
        int y=find_father(edge[i].y);
        if(x==y)continue;
        fa[x]=y;
    }
    s=read();t=read();
    if(find_father(s)!=find_father(t)){
        printf("IMPOSSIBLE");
        return 0;
    }
    sort(edge+1,edge+m+1,cmp);
    for(register int i=1;i<=m;i++){    //定下一條最小邊,列舉比它大的邊並不斷往並查集裡面加,當s和t連通時找到的是這條小邊的最優解 
        for(register int j=1;j<=n;j++)fa[j]=j; 
        for(register int j=i;j<=m;j++){     //跑最小生成樹(反正資料小怎麼亂搞都行) 
            int x=find_father(edge[j].x);
            int y=find_father(edge[j].y);
            if(x!=y)fa[x]=y; 
//          cout<<s<<t;
            if(find_father(s)==find_father(t)){
//              cout<<l<<" "<<r<<endl;
                double sum=(double)edge[j].v/(double)edge[i].v;
//              cout<<sum<<endl;
                if(sum<ans){
                    ans=sum;
                    l=edge[j].v;
                    r=edge[i].v;
                }
            }
        }
    }
    if(l%r==0)printf("%d",l/r);
    else{
        int t=gcd(l,r);
        printf("%d/%d",l/t,r/t);
    }
    return 0;
}