[Algorithm]连通性问题 Connectivity Problem

问题描述

已知一个整数对(pair)序列,每个整数代表一个对象,将p-q解释成p与q连通。连通是可传递的,例如p与q连通,q与r连通,则p与r连通。写一段程序,从集合中过滤多余的连接对。即当输入一个对p-q,仅当程序不能通过可传递性证明p与q连通时,才输出该对。

代码示例

快速查找 quick-find

/* 连通性问题 Connectivity
 * 快速查找 quick-find
 * 慢速并集
 */
#include <stdio.h>
#define N 1000
int main(void)
{
	int i, p, q, t, id[N];
	for(i = 0; i < N; i++)
		id[i] = i;
	while(scanf("%d %d", &p, &q) == 2)
	{
		if(id[p] == id[q]) continue;        //连通,进入下个循环
		for(t = id[p], i = 0; i < N; i++)   //所有id与id[p]比较,赋值给t防止id[p]被覆盖
			if(id[i] == t) id[i] = id[q];//更新连通对的id
		printf("output: %d %d\n", p, q);
	}
	return 0;
}

快速并集 quick-union

/* 连通性问题 Connectivity
 * 快速并集 quick-union
 *
 */
#include <stdio.h>
#define N 1000
int main(void)
{
	int i, j, p, q, t, id[N];
	for(i = 0; i < N; i++)
		id[i] = i;
	while(scanf("%d %d", &p, &q) == 2)
	{
		for(i = p; i != id[i]; i = id[i]);    //寻找p对应的根节点
		for(j = q; j != id[j]; j = id[j]);    //根节点判断,i==id[i]
		if(i == j) continue;                  //已连通,进入下个循环
		id[i] = j;                            //修改p的根节点指向q的根节点
		printf("output: %d %d\n", p, q);
	}
	return 0;
}

加权快速并集 weighted-quick-union

/* 连通性问题 Connectivity
 * 加权快速并集 weighted-quick-union
 *
 */
#include <stdio.h>
#define N 1000
int main(void)
{
	int i, j, p, q, t, id[N], sz[N];
	for(i = 0; i < N; i++)
	{id[i] = i; sz[i] = 1;}
	while(scanf("%d %d", &p, &q) == 2)
	{
		for(i = p; i != id[i]; i = id[i]);    //寻找p对应的根节点
		for(j = q; j != id[j]; j = id[j]);    //根节点判断,i==id[i]
		if(i == j) continue;                  //已连通,进入下个循环
		if(sz[i] < sz[j])                     //i的节点数小于j
		{id[i] = j; sz[j] += sz[i];}          //把i连接到j上,j的节点数加上i的节点数
		else {id[j] = i; sz[i] += sz[j];}     //把j连接到i上,i的节点数加上j的节点数
		printf("output: %d %d\n", p, q);
	}
	return 0;
}

对分路径压缩加权快速并集 weighted-quick-union-with-path-compression-by-halving

/* 连通性问题 Connectivity
 * 对分路径压缩加权快速并集 weighted-quick-union-with-path-compression-by-halving
 *
 */
#include <stdio.h>
#define N 1000
int main(void)
{
	int i, j, p, q, t, id[N], sz[N];
	for(i = 0; i < N; i++)
	{id[i] = i; sz[i] = 1;}
	while(scanf("%d %d", &p, &q) == 2)
	{
		for(i = p; i != id[i]; i = id[i])    //寻找p对应的根节点,根节点判断id[i]==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])                     //i的节点数小于j
		{id[i] = j; sz[j] += sz[i];}          //把i连接到j上,j的节点数加上i的节点数
		else {id[j] = i; sz[i] += sz[j];}     //把j连接到i上,i的节点数加上j的节点数
		printf("output: %d %d\n", p, q);
	}
	return 0;
}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值