[HAOI2006] 旅行
传送门:>HERE<
题意:给出一副无向图,求从S到T的任意一条路径中,最大边权与最小边权比值的最小值
解题思路:
由于数据范围很小,可以考虑$O(m^2)$的算法。
刚开始一直很困惑,不就跑一边求一个最大最小比一比吗,为什么还有最小值?太thick了,作为一个无向图,只要两点连通,路径可能多到不知哪里去了。而最大最小值是在同一条路径上的。那么如果Dfs呢,又太慢了。
我们考虑,如果路径上的最小值已经确定了,那么只要找到剩余路径中最小的最大值就可以了。这好像让我们联想到了Kruscal算法——将所有边排序,枚举最小值(其实就是排序后一条一条枚举)。选定了每一条最小边以后,一条条将剩余的比它大的边插入,直到S和T连通为止——此时的边权一定是最小的最大值了。(单调)。这个过程用并查集就行了。
再加上一点分数的处理。复杂度大约$O(m^2\ log\ n)$
Code
/*By QiXingzhi*/ #include <cstdio> #include <queue> #include <cstdlib> #include <algorithm> #define r read() #define Max(a,b) (((a)>(b)) ? (a) : (b)) #define Min(a,b) (((a)<(b)) ? (a) : (b)) using namespace std; typedef unsigned long long ll; const int N = 510; const int M = 5010; const int INF = 1061109567; inline int read(){ int x = 0; int w = 1; register int c = getchar(); while(c ^ '-' && (c < '0' || c > '9')) c = getchar(); if(c == '-') w = -1, c = getchar(); while(c >= '0' && c <= '9') x = (x << 3) +(x << 1) + c - '0', c = getchar(); return x * w; } struct Edge{ int u,v,w; }a[M]; struct Frac{ int x,y; }ans; int n,m,x,y,z,S,T,par[N]; inline bool FracCompare(Frac _a, Frac _b){ return !(_a.x * _b.y < _b.x * _a.y); } int gcd(int a, int b){ return !b ? a : gcd(b, a%b); } inline void PrintAns(Frac __a){ int g = gcd(__a.x, __a.y); __a.x /= g, __a.y /= g; if(__a.y == 1){ printf("%d",__a.x); else printf("%d/%d",__a.x, __a.y); } inline bool comp(const Edge& a, const Edge& b){ return a.w < b.w; } int find(int x){ return par[x] == x ? x : par[x] = find(par[x]); } inline void Try(int _t){ for(int i = 1; i <= n; ++i) par[i] = i; int A,B,__max=-1; for(int i = _t; i <= m; ++i){ A = find(a[i].u), B = find(a[i].v); if(A != B) par[A] = B; if(find(S) == find(T)){ __max = a[i].w; break; } } if(__max != -1){ Frac _tmp1; _tmp1.x = __max, _tmp1.y = a[_t].w; if(FracCompare(_tmp1, ans) == 0) ans = _tmp1; } } inline void JudgeConnect(){ int A,B; for(int i = 1; i <= n; ++i) par[i] = i; for(int i = 1; i <= m; ++i){ A = find(a[i].u), B = find(a[i].v); if(A != B) par[A] = B; } if(find(S) != find(T)) printf("IMPOSSIBLE"), exit(0); } int main(){ n = r, m = r; for(int i = 1; i <= m; ++i) a[i].u = r, a[i].v = r, a[i].w = r; S = r, T = r; sort(a+1, a+m+1, comp); JudgeConnect(); ans.x = INF; ans.y = 1; for(int i = 1; i <= m; ++i) Try(i); PrintAns(ans); return 0; }