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;
}