codevs 1001 舒适的路线 解题报告 (枚举+并查集)

在线评测:

http://codevs.cn/problem/3027/


整体思路:

我们可以先把边排序,然后我们想一下,我们要求一条路,这条路上的最大值和最小值的比值最小,那么显然,我们应该是最大值一定的情况下,最小值尽可能的大。所以我们排完序之后,我们从长边到短边开始枚举最大边,然后我们从这条边开始往下枚举,每次把边的两点联通,然后判断起点终点是否联通,如果联通,则用当前选取的最大边和最小边尝试更新答案。最后求出最优情况下最大边和最小边的大小之后,如果不能整除,gcd一下搞成分数就行了!


失误之处:

我开了一个全局变量minn,来尝试记录当当前最大边为某边时,最小边的权值,然而我没有在每次枚举最大边后将其清零,在判断是否更新答案的时候也没有进行判断当前情况下到底图是否联通,于是存在枚举这个最大边往下根本无法联通,但我还调用了以前的minn来进行计算,最后算出了一些远远小于1的值。实在是一个很大的失误!!!!


体会心得:

一定要考虑会不会误用到上次循环遗留的变量。

不要过于追求开全局变量,适当使用局部变量有时候更能提醒自己进行初始化~~

AC代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
#include <cstdio>
#include <cmath>
#include <cstring>
#include <algorithm>
using  namespace  std;
struct  lx
{
     int  x, y,w;
};
bool  operator < ( const  lx &x, const  lx &y)
{
     return  x.w > y.w;
}
int  n,m,s,t,fa[1000],size[1000];
int  maxn,minn,amaxn,aminn;
double  pmin;
lx sz[10001];
bool  lt;
int  getfa( int  x)
{
     if  (fa[x] == x)  return  x;
     return  fa[x] = getfa(fa[x]);
}
void  merge( int  x, int  y)
{
     if  (getfa(x) == getfa(y))  return ;
     int  s1 = getfa(x),s2 = getfa(y);
     if  (size[s1] < size[s2])
     {
         fa[s1] = s2;
         size[s2] += size[s1];
     } else
     {
         fa[s2] = s1;
         size[s1] += size[s2];
     }
}
void  init()
{
     for  ( int  i = 1;i <= n;i++)
         fa[i] = i,size[i] = 1;
}
int  gcd( int  x, int  y)
{
     return  !y ? x :gcd(y,x % y);
}
int  main()
{
     pmin = 9999999999999.0;
     scanf ( "%d%d" ,&n,&m);
     for  ( int  i = 1;i <= m;i++)
     {
         scanf ( "%d%d%d" ,&sz[i].x,&sz[i].y,&sz[i].w);
     }
     scanf ( "%d%d" ,&s,&t);
     sort(sz+1,sz+m+1);
     for  ( int  i = 1;i < m;i++)
     {
         init();
         maxn = sz[i].w;
         merge(sz[i].x,sz[i].y);
         if  (getfa(s) == getfa(t))
         {
             amaxn = sz[i].w;
             aminn = sz[i].w;
             lt =  true ;
             break ;
         }
         minn = 0; //就是开始在这个位置没有初始化 
         for  ( int  j = i+1;j <= m;j++)
         {
             merge(sz[j].x,sz[j].y);
             if  (getfa(s) == getfa(t))
             {
                 lt =  true ;
                 minn = sz[j].w;
                 break ;
             }
         }
         double  t1 = maxn,t2 = minn;
         if  (minn) //这个位置也没有判0 
         if  ((t1 / t2) < pmin)
         {
             pmin = t1 / t2;
             amaxn = maxn;
             aminn = minn;
         }
     }
     if  (!lt)  printf ( "IMPOSSIBLE\n" ); else
     {
         if  (!(amaxn % aminn))  printf ( "%d\n" ,amaxn / aminn); else
         {
             int  tp = gcd(amaxn,aminn);
             printf ( "%d/%d\n" ,amaxn/tp,aminn/tp);
         }
     }
     return  0;
}


评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值