思路就是并查集+枚举
把每条边按速度排序,从大到小枚举大的边,然后再枚举小的边,都并到一个集合中,如果发现起始点和终止点在一个集合中了,说明当前的边就是当前最大边中的最小边,然后用这个比值更新最终结果,不要忘记约分,而且如果最小边是最大边的因数的话也要特判。
还有就是浮点数的处理,把大边改成浮点型再比上小边,不然codevs只能对三个点
上码:
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #include<cmath> using namespace std; int n, m; int x, y; int pre[501]; int high[501]; struct line { int to; int from; int w; }; line edge[5001]; void init() { for (int i = 1;i <= n;i++) { pre[i] = i; high[i] = 0; } } int find(int x) { if (pre[x] == x)return x; else return pre[x] = find(pre[x]); } void unite(int x, int y) { x = find(x); y = find(y); if (high[y] > high[x])pre[x] = y; else { pre[y] = x; if (high[x] == high[y])high[x]++; } } bool cmp(const line& a, const line& b) { return a.w > b.w; } int gcd(int a, int b) { if (b == 0)return a; else return gcd(b, a%b); } int main() { cin >> n >> m; int max1 = 9999999; int min1 = 1; for (int i = 1;i <= m;i++) { cin >> edge[i].from >> edge[i].to >> edge[i].w; } cin >> x >> y; sort(edge + 1, edge + 1 + m,cmp); for (int i = 1;i <= m;i++) { init(); for (int j = i;j <= m;j++) { unite(edge[j].from, edge[j].to); if (find(x) == find(y)) { if (float(max1) / min1 > float(edge[i].w) / edge[j].w) { max1 = edge[i].w; min1 = edge[j].w; } break; } } } int yue = gcd(max1, min1); if (max1 == 9999999 && min1 == 1)cout << "IMPOSSIBLE"; else if (yue == 1)cout << max1 << "/" << min1; else if (yue == min1)cout << max1 / min1; else cout << max1 / yue << "/" << min1 / yue; return 0; }