[关闭]
@xingxing 2017-02-05T14:17:21.000000Z 字数 1666 阅读 685

专题四 并查集&生成树

并查集&生成树


[题目][A]

How Many Tables

题目大意:

有T个(1 <= T <= 25)个测试样例,每个测试样例中有一个n,m(1 <= n,m <= 1000),表示有n个人(编号1到n),然后下面m行表示,a和b认识。只有相互认识的人(直接或间接)才能坐一桌,最后输出最少需要坐多少张桌子。

解题思路:

对于每个测试样例,根据m行表示朋友关系的a,b,进行并查集合并,然后看有多少个不同的集合,也就是最少的桌子数。
时间复杂度O(T*(n+m)),空间复杂度O(n).

AC代码:

  1. #include <iostream>
  2. #include <cstdio>
  3. #include <cstdlib>
  4. #include <cstring>
  5. using namespace std;
  6. const int maxn = 1003;
  7. int pre[maxn];
  8. int root[maxn];
  9. int Find(int x)
  10. {
  11. int r = x;
  12. while(r != pre[r]) r = pre[r];
  13. int i = x,j;
  14. while(pre[i] != r)
  15. {
  16. j = pre[i];
  17. pre[i] = r;
  18. i = j;
  19. }
  20. return r;
  21. }
  22. void mix(int a,int b)
  23. {
  24. int fa = Find(a),fb = Find(b);
  25. if(fa != fb)
  26. {
  27. pre[fb] = fa;
  28. }
  29. }
  30. int main()
  31. {
  32. int t;
  33. int i;
  34. int n,m;
  35. int a,b;
  36. int ans;
  37. scanf("%d",&t);
  38. while(t--)
  39. {
  40. scanf("%d%d",&n,&m);
  41. for(i = 1;i <= n;i++)
  42. pre[i] = i;
  43. for(i = 1;i <= m;i++)
  44. {
  45. scanf("%d%d",&a,&b);
  46. mix(a,b);
  47. }
  48. memset(root,0,sizeof(root));
  49. for(i = 1;i <= n;i++)
  50. {
  51. root[Find(i)] = 1;
  52. }
  53. for(ans = 0,i = 1;i <= n;i++)
  54. {
  55. if(root[i]) ans++;
  56. }
  57. printf("%d\n",ans);
  58. }
  59. return 0;
  60. }

[题目][B]

Corporative Network

题目大意:

测试样例有T个。
有N个点(5 <= N <= 20000),执行如下3种指令:
E m:  输出m到根的距离(m到根中,每一段距离之和)
I a b: a接到b上,即a的前驱变为b。
O:    指令执行结束。

解题思路:

并查集。按顺序执行指令(x个(x <= 200000 )),执行E时,就查找m,然后输出dis[m],并且进行路径压缩,同时修改m的前驱为根,并且更新这条路径上的点到根的距离。执行I时,把a的前驱改为b,并且修改ab之间的距离为|a-b|%1000。
时间复杂度O(t*(n+x)),空间复杂度O(n).

AC代码:

  1. #include <iostream>
  2. #include <cstdio>
  3. #include <cmath>
  4. #include <algorithm>
  5. using namespace std;
  6. const int maxn = 20000+5;
  7. int dis[maxn];
  8. int root[maxn];
  9. int n;
  10. void init()
  11. {
  12. int i;
  13. for(i = 1;i <= n;i++)
  14. {
  15. dis[i] = 0;
  16. root[i] = i;
  17. }
  18. }
  19. int findr(int m)
  20. {
  21. int x;
  22. if(root[m] == m) return m;
  23. x = root[m];
  24. root[m] = findr(root[m]);
  25. dis[m] += dis[x];
  26. return root[m];
  27. }
  28. int main()
  29. {
  30. int t;
  31. char ch;
  32. int a,b;
  33. int m;
  34. scanf("%d",&t);
  35. while(t--)
  36. {
  37. scanf("%d",&n);
  38. init();
  39. while(scanf("%c",&ch) && ch != 'O')
  40. {
  41. if(ch == 'E')
  42. {
  43. scanf("%d",&m);
  44. findr(m);
  45. printf("%d\n",dis[m]);
  46. }
  47. if(ch == 'I')
  48. {
  49. scanf("%d%d",&a,&b);
  50. root[a] = b;
  51. dis[a] = abs(a-b)%1000;
  52. }
  53. }
  54. }
  55. return 0;
  56. }
添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注