problem4:连通性问题
假如已知一个整数对序列,其中每个整数代表某种类型的一个对象,而且将p-q对解释成"p与q连通"。假定连通关系是可传递的,即:如果p与q连通,同时q与r连通,则p与r也连通。
任务:编写一个程序,从一个整数对结合中过滤额外的链接对。即当程序输入一个整数对p-q,仅当程序此时已经看到的对不能通过可传递性证明p与q连通时,它才输出该对。如果前面的对表明p与q连通,则程序应该忽略p-q,并且继续输入下一个对。
样列输入:
3 4
4 9
8 0
2 3
5 6
2 9
5 9
7 3
4 8
5 6
0 2
6 1
样列输出:
3 4
4 9
8 0
2 3
5 6
5 9
7 3
4 8
6 1
恩,大家回答得都比较对,这个题目的最好解答就是用并集查找,ysg同学的算法实现了直接的并集查找但是对于有N个对象何M个对的连通性问题,ysg同学的算法时间复杂度为O(M*N)。而事实上,正如他所说在实现时,可以通过开辟一个数组来保存每颗树的节点数,在连通时,总是连通较小的树连接到较大树,这样可以保证在判断N个对象的其中两个对象是否连通时,最多需要跟踪2lgN个节点,最后的优化的就是进行路径压缩。
以下是paoblem4的一个比较好的实现,在路径压缩时使用的是对分路径压缩。具体过程请大家自己分析一下语句,顺便分析一下算法的性能,并且思考如何产生一组输入序列使下面程序生成一条长度为5的搜索路径.
#include <stdio.h>
#define MAX_N 10000
int main() {
int i, j, p, q;
int id[MAX_N], sz[MAX_N];
for (i = 0; i < MAX_N; ++i) {
id[i] = i;
sz[i] = 1;
}
while (scanf("%d %d", &p, &q) == 2) {
for (i = p; i != id[i]; i = id[i])
id[i] = id[id[i]];
for (j = q; j != id[j]; j = id[j])
id[j] = id[id[j]];
if (i == j) continue;
if (sz[i] < sz[j]) {
id[i] = j;
sz[j] += sz[i];
} else {
id[j] = i;
sz[i] += sz[j];
}
printf("%d/t%d/n", p, q);
}
return 0;
}