HDU-1856-More is better (并查集)

 

 

题目传送门:http://acm.hdu.edu.cn/showproblem.php?pid=1856

 

程序分析:

  一个老板要完成一个项目,需要一些人来帮忙,越多越好,但是有个条件,这些人都应该彼此认识(直接跟间接),有个隐含的是如果没人可以帮忙,只好自己上阵,干活的就只有自己一个了。输入的是一对一对的朋友,他们都彼此认识。人数可以达到一千万(10000000)。

解决方法:  

  并查集可以解决,都是把认识的挂同一棵树上,最后统计那棵树最多人,结果就是这棵树的人数了。由于n巨大,所以需要对输入的人编号进行标记(0/-1),还有统计输入的人里面编号最大的那个。只有在下面循环统计最大树时速度才能加快。开数组时要注意,必须开比一千万大一点,但是只能开两个这样的数组,因为开到第三个时内存以经超过题目要求了,就是这里我WA了好几次内存超的。在编写并查集初始化函数时里面的for循环里的 i 不能 等于 Max,这样会跑到不是你申请的内存里初始化,虽然编译器不会报错,但是属于访问非法内存,这个问题还是让我WA了无数次后才发现。最后也没什么特别要注意的了。看代码吧。属于简单并查集题,陷阱可能就是输入0时要输出 1 吧。

  

 

 

 

 

 

 

 

 

 

 

 

 

View Code
 1 #include<iostream>
 2 #include<string>
 3 using namespace std;
 4 
 5 const long Max = 10000000+10;
 6 long Far[Max];
 7 //long Rank[Max];  //这个数组不能在开了,开了就爆内存咯
 8 long Num[Max];
 9 
10 void Make_set(long n)
11 {
12     long i;
13     for(i=0; i<n; i++)  //不能是i<=n ,  会跑到不是你申请的内存里去初始化,这个问题是最后才发现的
14     {
15         Far[i] = i;
16     }
17     //memset(Rank, 0, sizeof(Rank));
18     memset(Num, -1, sizeof(Num));  //把所有人的数量都初始化为-1,表示未存在,下面如果有输入时就标记为0
19 }
20 
21 long Find(long x)
22 {
23     if(Far[x] != x)
24         return Far[x] = Find(Far[x]);
25     return x;
26 }
27 
28 void Unio(long a, long b)
29 {
30     a = Find(a);
31     b = Find(b);
32     if(a == b)
33         return ;
34     Far[a] = b;
35 
36     //  木有开Rank数组,只好全部默认把a挂在b树上
37 
38     /*if(Rank[a] < Rank[b])
39         Far[a] = b;
40     else if(Rank[a] > Rank[b])
41         Far[b] = a;
42     else
43     {
44         Far[a] = b;
45         Rank[b]++;
46     }*/
47 }
48 
49 int main()
50 {
51     long n;
52     while(scanf("%ld", &n) != EOF)
53     {
54         if(n == 0)   //输入n为0时,应该就是表示木有人可以帮忙,只好亲自上阵了吧,
55                      //那么干活的就只有自己一个了,老板嘛,有人帮忙自己就不会去做的
56         {
57             cout<<1<<endl;
58             continue;
59         }
60         Make_set(Max);
61         long Num_max = 0;
62         for(long i=0; i<n; i++)
63         {
64             long a, b;
65             scanf("%ld%ld", &a, &b);
66             Num[a] = Num[b] = 0;  //把有的人都标记为0
67             Num_max = Num_max > (a>b?a:b) ? Num_max:(a>b?a:b); //记录下最大的人编号,在下面找老大时可以减少一些判断
68             Unio(a, b);
69             
70         }
71         long max = 0;
72         for(long j=1; j<=Num_max; j++)
73         {    
74             if(Num[j] >= 0)  //不小于0就表示存在于这些树里
75             {    
76                 Num[Find(j)]++;  //以Find(j)为老大的树的结点加一
77                 if(Num[Far[j]] > max)
78                     max = Num[Far[j]];  //统计最大结点数量的树
79             }
80         }
81         printf("%ld\n", max);
82     }
83     return 0;
84 }

 

posted @ 2012-08-26 10:15  另Ⅰ中Feel▂  阅读(215)  评论(0编辑  收藏  举报