「Bzoj 1050」「HAOI2006」旅行comf (最小瓶颈路)

Bzoj 1050
求$s-​>t$的路径上最大边权与最小边权的比值最小,就是让最小边权尽量接近最大边权。
我们枚举每一边作为最小边权,然后我们将边权大于该边权的边按边权大小依次连上,直到$s$与$t$连通,那么这样$s->t$的路径上的最大边权一定是最后加的这个边,因为加了这条边使得$s$与$t$连通。这条路径上的边权都是大于等于最小边权小于等于最大边权,而最小生成树保证最大边权最小,也就是最小瓶颈路,所以这样就解决了问题。
注意可能有最小边就是最大边的情况,这种情况下答案为$1$

求两点问题,用一点去求另一点,是一个很好的方法

#include<cstdio>
#include<cstring>
#include<algorithm>
#define ms(i, j) memset(i, j, sizeof i)
#define LL long long
#define db double
using namespace std;
const int MAXN = 500 + 5, MAXM = 5000 + 5;
struct data {
    int u, v, wi;
    bool operator < (const data &b) const {
        return wi < b.wi;
    }
}e[MAXM];
int ans1, ans2, s, t, en, n, m, f[MAXN];
db ans;
int gcd(int a, int b) {return (b == 0) ? a : gcd(b, a % b);}
int find(int x) {return f[x] == x ? x : f[x] = find(f[x]);}
void clean() {
    ans1 = ans2 = en = 0, ans = 1000000000.0;
}
void solve() {
    clean();
    for (int i=1;i<=m;i++) {
        en++, scanf("%d%d%d", &e[en].u, &e[en].v, &e[en].wi);
    }
    scanf("%d%d", &s, &t);
    sort(e + 1, e + 1 + m);
    for (int i=1;i<=m;i++) {
        for (int j=1;j<=n;j++) f[j] = j;
        int maxi = 0;
        //不要先连这边,因为有最小边和最大边相同的情况 
        for (int j=i;j<=m;j++) {
            int x = find(e[j].u), y = find(e[j].v);
            if (x != y) f[x] = y, maxi = e[j].wi;
            x = find(s), y = find(t);
            if (x == y) {
                int tmp = e[i].wi;
                if (maxi < tmp) swap(maxi, tmp);
                if (ans > (db)maxi / (db)tmp) {
                    ans = (db)maxi / (db)tmp;
                    ans1 = maxi, ans2 = tmp;
                }
                break;
            }
        }
    }
    if (ans1 == 0) printf("IMPOSSIBLE\n"); else
    if (ans1 % ans2 == 0) printf("%d\n", ans1 / ans2); else {
        int g = gcd(ans1, ans2);
        printf("%d/%d\n", ans1 / g, ans2 / g);
    }
}
int main() {
    #ifndef ONLINE_JUDGE 
    freopen("1.in", "r", stdin);freopen("1.out", "w", stdout);
    #endif
    scanf("%d%d", &n, &m), solve();
    return 0;
}
------ 本文结束 ------