背景 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;
}