[HAOI2006]旅行

洛谷题目链接:旅行

题目描述

Z小镇是一个景色宜人的地方,吸引来自各地的观光客来此旅游观光。Z小镇附近共有N个景点(编号为1,2,3,…,N),这些景点被M条道路连接着,所有道路都是双向的,两个景点之间可能有多条道路。也许是为了保护该地的旅游资源,Z小镇有个奇怪的规定,就是对于一条给定的公路Ri,任何在该公路上行驶的车辆速度必须为Vi。速度变化太快使得游客们很不舒服,因此从一个景点前往另一个景点的时候,大家都希望选择行使过程中最大速度和最小速度的比尽可能小的路线,也就是所谓最舒适的路线。

输入输出格式

输入格式:

第一行包含两个正整数,N和M。

接下来的M行每行包含三个正整数:x,y和v。表示景点x到景点y之间有一条双向公路,车辆必须以速度v在该公路上行驶。

最后一行包含两个正整数s,t,表示想知道从景点s到景点t最大最小速度比最小的路径。s和t不可能相同。

输出格式:

如果景点s到景点t没有路径,输出“IMPOSSIBLE”。否则输出一个数,表示最小的速度比。如果需要,输出一个既约分数。

输入输出样例

输入样例#1: 
4 2
1 2 1
3 4 2
1 4
输出样例#1: 
IMPOSSIBLE
输入样例#2: 
3 3
1 2 10
1 2 5
2 3 8
1 3
输出样例#2: 
5/4
输入样例#3: 
3 2
1 2 2
2 3 4
1 3
输出样例#3: 
2

说明

【数据范围】

1<N≤500

1≤x,y≤N,0<v<30000,x≠y

0<M≤5000

这道题的题意大概就是给出一个无向图,求起点S与终点T间能否联通,如果可以联通,则求出这条路径上最大权值与最小权值的比值。

首先如果不考虑这个权值比值的关系,那么这道题可以直接用Kruskal来建一个生成树判断能否联通(当然也可以用别的方法来判断),那么如果有比值这个条件应该怎么判断?我们不好确定要用哪些边来连一条路径,但是显然是先将权值进行排序,然后取其中数组下标连续的一些边来连接是最优的(想一想为什么)。那么我们就可以来枚举一个边权的最小值,然后不断连边,直到S,T连通,如果可以连通了,就停止继续连边,因为再继续连边会使得最大值变大,无法使答案更优。然后这个题目就可以转化成了一个枚举最小边权的生成树,算法时间复杂度为O(m*(m+n))。然后就是一些判断输出方式的小技巧了。

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 const int N=500;
 4 const int M=5000;
 5 const int inf=2147483647;
 6 
 7 int s, t;
 8 int n, m;
 9 int fa[N];
10 int mn, mx;
11 int ans1 = inf, ans2 = 1;
12 
13 struct bian{
14     int st, ed, w;
15     bool operator < (const bian &a){
16     return w < a.w;
17     }
18 }a[M];
19 
20 int find(int x){
21     if(x == fa[x]) return x;
22     return fa[x] = find(fa[x]);
23 }
24 
25 int Gcd(int a,int b){
26     return b==0?a:Gcd(b,a%b);
27 }
28 
29 int main(){
30     //freopen("data.in","r",stdin);
31     cin >> n >> m;
32     for(int i=1;i<=m;i++)
33     cin >> a[i].st >> a[i].ed >> a[i].w;
34     cin >> s >> t;
35     sort(a+1 , a+m+1);
36     for(int i=1;i<=m;i++){
37         int mn = inf , mx = -inf;
38         for(int j=1;j<=n;j++) fa[j] = j;
39         for(int j=i;j<=m && find(s)!=find(t);j++){
40             int r1 = find(a[j].st) , r2 = find(a[j].ed);
41             if(r1 != r2){
42                 fa[r1] = r2;
43                 mn = min(mn , a[j].w);
44                 mx = max(mx , a[j].w);
45             }
46         }
47         if(find(s) == find(t) && double (ans1*1.0/ans2) > double (mx*1.0/mn))
48         ans1 = mx , ans2 = mn;
49     }
50     int gcd = Gcd(ans1 , ans2);
51     if(ans1 == inf){printf("IMPOSSIBLE
"); return 0;}
52     if(gcd == ans2) printf("%d
",ans1/ans2);
53     else printf("%d/%d
",ans1/gcd,ans2/gcd);
54     return 0;
55 }
原文地址:https://www.cnblogs.com/BCOI/p/8616608.html