数据结构与算法实验题 11.1 堆箱子问题 ★ 问题描述 : ACM 小组要搬实验室了! ACM 小组的组员决定把实验室中的物品先放入 N(1<=N<=30000) 个箱子,然后把这些箱子叠放成几堆。由于每个箱子里放的都 是易碎物品,因此,要求每个箱子的上面不能堆过多的箱子。现在, ACM 队员 准备请你写一个程序,来快速得出某个箱子的下面有几个箱子。 ★ 实验任务: ACM 队员对箱子的操作只有两种: ( 1 ) D x y :把含 x 的那一叠箱子按 照 原来的顺序全部堆到含 y 的那一 叠 箱 子的最 上面。 ( 2 ) C x :计算 含 x 的箱子下面有几个箱子,并输出。 请你写个程序实现以上功能。 ★ 数据输入: 输入数据由 input.txt 提供。第一行是一个整数 P(1<=P<=100000) ,表明 AC M 队员进行了 P 次操作。接下来 P 行,每行表示一种操作,即 D x y 或 C x ,其中 x 和 y 是箱子编号, 编号 从 1 到 N 。题目保证数据是符合逻辑的,即不会把含 x 的 箱子堆到 x 上面。 ★ 结果输出 : 结果输出到 output.txt 。每个 C x 操作输出一行,表示 x 下面有几个箱子。 输入示例 输出示例 input.txt 6 D 1 6 D 2 4 C 1 D 2 6 C 3 C 4 output.txt 1 0 2 并查集合,注意查找的时候需要进行更新值的操作,而且也不可以大树合并小树。 还有合并集合用的递归方法。是自上而下的。 #include <stdio.h> #include <string.h> class CUnion_Set { public: CUnion_Set(int n = 10); ~CUnion_Set(){delete []num;delete []parent;delete []up;} void Union(int a, int b); int Find(int a); int GetTotalNum(int a){return num[a];} int GetUpNum(int a){return up[a];} private: int *num; int *parent; int *up; }; CUnion_Set::CUnion_Set(int n /* = 10 */) { num = new int[n]; parent = new int[n]; up = new int[n]; for (int i=0;i<n;i++) { num[i] = 1; parent[i] = i; up[i] = 0; } } int CUnion_Set::Find(int a) { int pre; if (parent[a] != a) { pre = parent[a]; parent[a] = Find(parent[a]); up[a] += up[pre]; } return parent[a]; } //a在b之上 void CUnion_Set::Union(int a, int b) { int ra = Find(a); int rb = Find(b); parent[rb] = ra; up[rb] = num[ra]; num[ra] += num[rb]; } int main() { int n,a,b; char c; int i; while (scanf("%d", &n)!=EOF) { CUnion_Set USet(n+1); for (i=0;i<n;i++) { while (scanf("%c", &c), c=='/n'); switch (c) { case 'D': scanf("%d%d", &a, &b); USet.Union(a, b); break; case 'C': scanf("%d", &a); printf("%d/n", USet.GetTotalNum(USet.Find(a))-USet.GetUpNum(a)-1); break; } } } return 0; }