NOIP2010 关押罪犯 解题报告(并查集,补集判断思想)

4 篇文章 0 订阅
3 篇文章 0 订阅

在线评测:

http://codevs.cn/problem/1069/


整体思路:

首先看到了题,我们的思路很简单,尽可能的去规避怨恨较大的案件,于是将关系按照影响坏的程度排序,并利用补集思想,将一个关系中的a,b两人

a与b的补集merge,b与a的补集merge。(这里我们开双倍数组,用sz[n+a] 来表示a的补集)不断的由大到小,当判断两个人已经同时存在于同意集合时,

即输出当前关系的影响,并return0;


失误之处:

1、没有考虑到结果为0的情况....

2、开始在将b与a merge的时候仅仅将a的fa接到了b的祖先上,而不是将a的祖先接到了b的祖先上,导致了集合判断的比较异常,WA了8个点

3、并查集的size初值填成了0,导致无论怎么加都是0,(多么蠢的事情,,,随便搞一个不大的正数就好了.....)

并查集那么简单,然而经常写错,所以来一份代码。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
struct  jd
{
     int  x;
     int  size;
};
jd fa[6000];
int  getfa( int  x)
{
     if  (fa[x].x == x)  return  x;
     return  fa[x].x = getfa(fa[x].x);
}
void  merge( int  x, int  y)
{
     int  s1 = fa[getfa(x)].size,s2 = fa[getfa(y)].size;
     if  (s1 < s2)
     {
         fa[getfa(x)].x = getfa(y);
         fa[getfa(y)].size += s1;
     } else
     {
         fa[getfa(y)].x = getfa(x);
         fa[getfa(x)].size += s2;
     }
}

体会心得:

1、常用的算法不要出现细节问题!!!!

2、全面考虑题意的结果!!


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
#include <cstdio>
#include <cmath>
#include <cstring>
#include <algorithm>
 
struct  lx
{
     int  fa,sz;
};
 
struct  lx1
{
     int  a, b, w;
};
 
lx sz[300000];
lx1 jl[300000];
int  n,m;
 
int  getfa( int  x)
{
     if  (sz[x].fa == x)  return  x;
     return  sz[x].fa = getfa(sz[x].fa);
}
 
void  merge( int  x, int  y)
{
     int  s1 = sz[getfa(x)].sz,s2 = sz[getfa(y)].sz;
     if  (s1 > s2)
     {
         sz[getfa(x)].fa = getfa(y);
         sz[getfa(y)].sz += s1;
     } else
     {
         sz[getfa(y)].fa = getfa(x);
         sz[getfa(x)].sz += s2;
     }
}
 
void  ycl()
{
     for  ( int  i = 1;i <= 300000;i++)
     {
         sz[i].fa = i;
         sz[i].sz = 1;
     }
}
 
bool  pd(lx1 a,lx1 b)
{
     if  (a.w > b.w)  return  true ;
     return  false ;
}
 
using  namespace  std;
int  main()
{
     ycl();
     scanf ( "%d%d" ,&n,&m);
     for  ( int  i = 1;i <= m;i++)
     {
         scanf ( "%d%d%d" ,&jl[i].a,&jl[i].b,&jl[i].w);
     }
     sort(jl+1,jl+m+1,pd);
     for  ( int  i = 1;i <= m;i++)
     {
         if  (getfa(jl[i].a) == getfa(jl[i].b))
         {
             printf ( "%d\n" ,jl[i].w);
             return  0;
         }
         sz[getfa(jl[i].a)].fa = getfa(jl[i].b + n);
         sz[getfa(jl[i].b)].fa = getfa(jl[i].a + n);
     }
     printf ( "0\n" );
     return  0;
}
(貌似好像没有用到merge函数,,,,,)


  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值