微子危机——建造

背景 Background

№.2
邪恶的Guiolk联盟采集好了微子能,就要运输。Guiolk联盟的领袖TT此时才发现,自己的军事基地中由微子发射器组成的微子能量网存在很大的问题,于是他决定修改。

描述 Description

之前,TT为了整齐,把军事基地建成了矩形,而且如果两个微子发射器的连线平行于军事基地的一边,这两个微子发射器之间就一定有微子能量传输线相连。
(*注:比如有3个微子发射器A(1,1)、B(1,3)、C(2,2),那么A和B之间有微子能量传输线相连,A和B不能传输到C。*)
但是在微子能运输过程中发现,常常不能从一个微子发射器运抵另一个微子发射器。
为了可以从任何一个微子传输器能运抵其它任意一个微子传输器,而且能和原来的微子能量网同样整齐,TT决定遵循原来的规则,调动他的百万农奴新修建一些微子能量传输线和微子发射器。由于微子发射器的造价比微子传输线高得多,所以TT决定忽略微子能量传输线的成本。
但是TT又不想花费不必要的钱,所以找到你为他计算最少需要建多少个微子发射器。

输入格式 InputFormat

第一行三个正整数n、m、p。(2<=n,m<=100000,表示军事基地的两边长;2<=p<=200000,表示微子发射器的个数。)
接下来p行,每行两个正整数数Xi、Yi(1<=Xi<=n  1<=Yi<=m),代表每个微子发射器在军事基地的位置。(可能会由于疏漏,有些微子发射器重复)

输出格式 OutputFormat

只有一行,为最少修建微子发射器的数量。

样例输入 SampleInput 

5 6 6
1 1
2 2
2 4
3 3
5 1
5 5

样例输出 SampleOutput 

2

数据范围和注释 Hint

样例的一种方案:
#.....
|#-#..
|.#+..
|.|...
#-+-#.

#表示原有微子发射器,-、|表示微子能量传输线,+表示兴建的微子发射器。所以至少兴建2个微子发射器。
如果看不清楚,请复制到记事本查看。

思路:

并查集应用。
#include <stdio.h>

int x[100001], y[100001], bcj[200002];       //x存x坐标对应的节点所在集合,y同理, bcj所有集合的并查集

int findfather(int x)
{
	if(bcj[x] == 0)
	{
		return x;
	}
	else
	{
		return findfather(bcj[x]);
	}
}

int merge(int sp, int ep)             //路径压缩(根节点改变时,改变所有以原根节点为根节点的节点, 以便压缩寻找根节点的的路径)
{
	int pre = sp, now;
	ep = findfather(ep);
	while(pre != 0)
	{
		now = pre;
		pre = bcj[now];
		if((pre == 0 && now != ep) || pre != 0)    //注意如果now==ep时,不能标记,否则就死循环了
		bcj[now] = ep;
	}
	return 0;
}

int main()
{
	int i, tx, ty, n, m, p, cnt, a, b, ans;
	cnt = 1;
	scanf("%d%d%d", &n, &m, &p);
	for(i = 0; i < p; i++)
	{
		scanf("%d%d", &tx, &ty);
		if(x[tx] == 0 && y[ty] == 0)
		{
			x[tx] = y[ty] = cnt;
			cnt++;
		}
		else if(x[tx] == 0 && y[ty] != 0)
		{
			x[tx] = y[ty];
		}
		else if(x[tx] != 0 && y[ty] == 0)
		{
			y[ty] = x[tx];
		}
		else
		{
			merge(x[tx], y[ty]);
		}
	}
	for(ans = 0, i = 1; i < cnt; i++)
	{
		if(bcj[i] == 0)
		{
			ans++;
		}
	}
	printf("%d\n", ans-1);
	return 0;
}


你可能感兴趣的:(merge,并查集)