【题目描述】
给定一个无向图,一个起点,一个终点,求一条路径,使得该路径上的最大边权与最小边权的比值最小。
$n \leq 500, m \leq 5000$
【题目链接】
BZOJ 1050 旅行comf [HAOI2006]
【解题思路】
枚举最大边,然后贪心,使最小边尽量大。
即对于枚举的最大边,将比其小的边从大到小依次加入,并查集维护连通性,当起点终点联通时跳出。
【AC代码】
#include <cstdio>
#include <algorithm>
#include <cfloat>
int gcd(int a, int b){
return b ? gcd(b, a % b) : a;
}
void reduce(int &x, int &y){
int g = gcd(x, y);
x /= g, y /= g;
}
const int MAXN = 500;
const int MAXM = 5000;
int n, m;
struct UnionFindSet{
int f[MAXN];
void init(){
for(int i = 0; i < n; i++){
f[i] = i;
}
}
int find(int x){
return f[x] == x ? x : f[x] = find(f[x]);
}
void merge(int x, int y){
f[find(x)] = find(y);
}
bool test(int x, int y){
return find(x) == find(y);
}
} ufs;
struct Edge{
int u, v;
int w;
} edges[MAXM];
bool operator<(const Edge &a, const Edge &b){
return a.w < b.w;
}
int s, t;
int p, q;
double ans; // ans = \frac p q;
inline void updateAns(int x, int y){
if((double)x / y < ans) p = x, q = y, ans = (double)x / y;
}
inline void printAns(){
if(ans == DBL_MAX){
puts("IMPOSSIBLE");
} else{
reduce(p, q);
if(q == 1){
printf("%d\n", p);
} else{
printf("%d/%d\n", p, q);
}
}
}
inline void solve(){
std::sort(edges, edges + m);
ans = DBL_MAX;
for(int i = 0; i < m; i++){
Edge *x = edges + i;
ufs.init();
for(int k = i; k >= 0; k--){
Edge *e = edges + k;
ufs.merge(e->u, e->v);
if(ufs.test(s, t)){
updateAns(x->w, e->w);
break;
}
}
}
printAns();
}
int main(){
scanf("%d%d", &n, &m);
for(int i = 0; i < m; i++){
Edge *e = edges + i;
scanf("%d%d%d", &e->u, &e->v, &e->w), e->u--, e->v--;
}
scanf("%d%d", &s, &t), s--, t--;
solve();
return 0;
}
就是这样啦