codevs 1001 舒适的路线(并查集) 题解


链接:http://codevs.cn/problem/1001/


中文题,挺有意思的,寻找S到T的路径中最长路段比最短路段比值最小的路径的比值。一开始用DFS深搜,果然TLE了,不过其实可以注意到假设我们找到了一条通路,他的路段最大值为a,最小值为b,那么我们任意添加长度为a到b之间的路段,都不会影响最终的比值,不管这些路段有没有用,所以,我们只需要对边排序过后,枚举路段最小值,然后往右遍历边,不断维护并查集来维护连通性,当新增一边之后F(x)==F(y),则起点终点联通了,这就是以那条边为最小值的路径中的最大边。最后gcd约分一下答案,注意一下可能一条边就使起点终点联通了。

/*
作者:sega_hsj
题目:p1001 舒适的路线
*/
#include<iostream>
#include<algorithm>
#include<string.h>
#include<stdio.h>
#include<vector>
#include<string>
#include<cmath>
#include<set>
#include<queue>
using namespace std;
#define ll long long
#define inf 0x3f3f3f3f
//const int mod = 1000000007;
const int maxm = 5005;
const int maxn = 505;
struct edge{
    int from, to, len;
}e[maxm];

int n, m,s,t;
int ansa,ansb;
int f[maxn];
bool vis[maxn];
int F(int x){
    if (f[x] == x)return x;
    return f[x] = F(f[x]);
}

bool cmp(edge a, edge b){
    return a.len < b.len;
}

int gcd(int a, int b){
    return b == 0 ? a : gcd(b, a%b);
}

int main() {
    int x, y, z;
    scanf("%d%d", &n, &m);
    ansa = -1;
    for (int i = 0; i < m; i++){
        scanf("%d%d%d", &x, &y, &z);
        e[i].from = x;
        e[i].to = y;
        e[i].len = z;
    }
    scanf("%d%d", &s, &t);
    sort(e, e + m, cmp);
    int cnta, cntb;
    for (int i = 0; i < m; i++){
        cnta=cntb = e[i].len;
        for (int i = 1; i <= n; i++){ f[i] = i; }
        f[e[i].to] = e[i].from;
        if (F(s) == F(t)){
            if (ansa == -1 || cntb*ansb < ansa*cnta){
                ansa = cntb, ansb = cnta;
            }
            break;
        }
        for (int j = i + 1; j < m; j++){
            cntb = e[j].len;
            f[F(e[j].to)] = F(e[j].from);
            if (F(s) == F(t)){
                if (ansa == -1 || cntb*ansb < ansa*cnta){
                    ansa = cntb, ansb = cnta;
                }
                break;
            }
        }
    }

    if (ansa == -1){ printf("IMPOSSIBLE"); }
    else{
        int c = gcd(ansa, ansb);
        ansa = ansa / c, ansb = ansb / c;
        if (ansb == 1){ printf("%d", ansa); }
        else{ printf("%d/%d", ansa, ansb); }
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值