卧薪尝胆,厚积薄发。
HAOI2006 旅行
Date: Mon Jul 16 23:31:55 CST 2018 In Category: NoCategory

Description:

给你一个无向图, $N$ 个顶点, $M$ 条边,每条边有一个权值 $V_i$ 。给你两个顶点 $S$ 和 $T$ ,求一条路径,使得路径上最大边和最小边的比值最小。
$1\le N \le 500$ $1\le M \le 5000$

Solution:

$M$ 只有 $5000$ , $O(M^2)$ 也可过,于是可以将边排序后枚举一个最小边,不断加边直到 $S$ 和 $T$ 联通,即可得到路径上最大边,更新答案即可。
如果 $M$ 更大,可以用 $LCT$ 维护生成树,每次把环中最小边 $cut$ 掉并加入新边。

Code:


#include<algorithm>
#include<iostream>
#include<cstdlib>
#include<cstdio>
#include<cmath>
#include<cstring>
using namespace std;
int n,m;
#define MAXM 5010
struct edge
{
int u,v,w;
}e[MAXM];
bool cmp(edge x,edge y){return x.w < y.w;}
#define MAXN 510
int f[MAXN];
int find(int x){return (x == f[x] ? x : f[x] = find(f[x]));}
int ans1,ans2;
int gcd(int a,int b){return (b == 0 ? a : gcd(b,a % b));}
int s,t;
int main()
{
ans1 = 0x3f3f3f3f,ans2 = 1;
scanf("%d%d",&n,&m);
for(int i = 1;i <= m;++i)scanf("%d%d%d",&e[i].u,&e[i].v,&e[i].w);
scanf("%d%d",&s,&t);
sort(e + 1,e + 1 + m,cmp);
bool found = false;
for(int i = 1;i <= m;++i)
{
for(int k = 1;k <= n;++k)f[k] = k;
for(int j = i;j <= m;++j)
{
int p = find(e[j].u),q = find(e[j].v);
if(p == q)continue;
f[p] = q;
if(find(s) == find(t))
{
found = true;
if(((double)ans1 / (double)ans2) > ((double)e[j].w / (double)e[i].w))
{
ans1 = e[j].w;ans2 = e[i].w;
}
break;
}
}
}
int t = gcd(ans1,ans2);
ans1 /= t;ans2 /= t;
if(!found)puts("IMPOSSIBLE");
else if(ans2 != 1)cout << ans1 << "/" << ans2 << endl;
else cout << ans1 << endl;
return 0;
}
In tag: 图论-kruskal
Copyright © 2020 wjh15101051
ღゝ◡╹)ノ♡