POJ--1988 cube stacking

╰+哭是因爲堅強的太久メ 2022-08-11 00:56 254阅读 0赞
  1. 关于这道题目,本来想到的是既然是搬箱子到另一堆上,那么我只要知道某一堆的底部箱子,和顶部的箱子即可。以底部的箱子为父亲节点,则顶部箱子就是以该箱子为父亲节点的到其距离最大的点。
  2. 因为每个节点到其根节点的距离是保存在各自的rank数组里的,所以应该是可行的。但是愚笨的我偏偏要把每一堆的点都要find一遍,结果当然TLE
  3. 1.方法行不通只能改进了,参考了别人的代码;把一堆最上面的箱子作为根,用数组rank表示x到其根节点的距离,用count\[x\]表示以x为根节的箱子的个数,则x下面的箱子个数很显然就是count\[ fx \] -rank\[x\]-1;
  4. #include <cstdio>
  5. #include <cstdlib>
  6. #include <cstring>
  7. #include <iostream>
  8. using namespace std;
  9. const int maxn=30005;
  10. int f[maxn],rank[maxn],count[maxn];
  11. void initial()
  12. {
  13. for(int i=0;i<maxn;i++)
  14. {
  15. f[i]=i;count[i]=1;
  16. }
  17. memset(rank,0,sizeof(rank));
  18. }
  19. int find(int x)
  20. {
  21. if(x==f[x])return x;
  22. int r=f[x];
  23. r=find(r);
  24. rank[x]+=rank[f[x]];
  25. return f[x]=r;
  26. }
  27. void Union(int x,int y)
  28. {
  29. int tx=find(x),ty=find(y);
  30. rank[ty]=count[tx];
  31. count[tx]+=count[ty];
  32. f[ty]=tx;
  33. }
  34. int main()
  35. {
  36. int P;
  37. scanf("%d",&P);
  38. initial();
  39. while(P--)
  40. {
  41. char s[5];int x,y;
  42. scanf("%s",s);
  43. if(s[0]=='M')
  44. {
  45. scanf("%d%d",&x,&y);
  46. Union(x,y);
  47. }
  48. else if(s[0]=='C')
  49. {
  50. scanf("%d",&x);
  51. int fx=find(x);
  52. printf("%d\n",count[fx]-rank[x]-1);
  53. }
  54. }
  55. return 0;
  56. }

2.这一种和上一种类似,不过是以箱子堆底部为根节点,rank[ x ]表示x到其根节点的距离,nNum[ x ]表示以x为根节点的堆的箱子数。

  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <string.h>
  4. #include <algorithm>
  5. using namespace std;
  6. const int MAX = 30010;
  7. int nSets[MAX];
  8. int nNum[MAX];
  9. int nRank[MAX];
  10. void MakeSets(int nN)
  11. {
  12. for (int i = 0; i < nN; ++i)
  13. {
  14. nSets[i] = i;
  15. nNum[i] = 1;
  16. nRank[i] = 0;
  17. }
  18. }
  19. int FindSet(int nI)
  20. {
  21. if (nSets[nI] != nI)
  22. {
  23. int nPre = nSets[nI];
  24. nSets[nI] = FindSet(nSets[nI]);
  25. nRank[nI] += nRank[nPre];
  26. }
  27. return nSets[nI];
  28. }
  29. void Move(int nX, int nY)
  30. {
  31. int nA = FindSet(nX);
  32. int nB = FindSet(nY);
  33. if (nA != nB)
  34. {
  35. nSets[nA] = nB;
  36. nRank[nA] += nNum[nB];
  37. nNum[nB] += nNum[nA];
  38. }
  39. }
  40. int main()
  41. {
  42. int nP;
  43. char szOper[10];
  44. int nX, nY;
  45. scanf("%d", &nP);
  46. MakeSets(MAX);
  47. while (nP--)
  48. {
  49. scanf("%s", szOper);
  50. if (szOper[0] == 'M')
  51. {
  52. scanf("%d%d", &nX, &nY);
  53. Move(nX, nY);
  54. }
  55. else
  56. {
  57. scanf("%d", &nX);
  58. FindSet(nX);
  59. printf("%d\n", nRank[nX]);
  60. }
  61. }
  62. return 0;
  63. }

3.这算是第二种方法的优化吧,去掉了一个数组,思想很巧妙。利用了f[ x ]的负值表示该节点为根节点和这一堆得箱子的个数…….,也就是去掉了count,其中nr数组为该箱子到其根节点的距离。

  1. #include <iostream>
  2. #include <cstdio>
  3. using namespace std;
  4. int cube[30330],nr[30330];
  5. int n;
  6. void make_set()
  7. {
  8. for(int i=0;i<=30030;++i)
  9. {
  10. cube[i] = -1;
  11. nr[i] = 0;
  12. }
  13. }
  14. int find_set(int x)
  15. {
  16. int tmp = cube[x];
  17. if(cube[x]<0)
  18. return x;
  19. cube[x] = find_set(cube[x]);
  20. nr[x] += nr[tmp];
  21. return cube[x];
  22. }
  23. void union_set(int n1,int n2)
  24. {
  25. int root1 = find_set(n1);
  26. int root2 = find_set(n2);
  27. int tmp = cube[root1];
  28. cube[root1] = root2;
  29. nr[root1] =nr[root1] - cube[root2];
  30. cube[root2] += tmp;
  31. }
  32. int main()
  33. {
  34. int i,j,root1,root2,n1,n2;
  35. char ch[1];
  36. cin>>n;
  37. make_set();
  38. while(n--)
  39. {
  40. scanf("%s ",ch);
  41. if(ch[0]=='M')
  42. {
  43. scanf("%d%d",&n1,&n2);
  44. union_set(n1,n2);
  45. }else if(ch[0]=='C')
  46. {
  47. scanf("%d",&n1);
  48. int tmp =find_set(n1);
  49. printf("%d\n",nr[n1]);
  50. }
  51. }
  52. return 0;
  53. }

发表评论

表情:
评论列表 (有 0 条评论,254人围观)

还没有评论,来说两句吧...

相关阅读

    相关 POJ 1988 Cube Stacking

    题目: POJ 1988 Cube Stacking ,哈哈,我们今天来看一道复杂一点的题嘛,这是选自POJ上的一道题,好了,我们一起来看看题意吧:考虑到直接复制题目,或...