问题
宇宙时间公元 5.55 亿年,由于某种原因两大联盟展开了激战(maxingc 联盟采用了微子技术):
邪恶的 maxingc 联盟采集好了微子能,就要运输。Maxingc 联盟的领袖 xc 此时才发现,自己的军事基地中
由微子发射器组成的微子能量网存在很大的问题,于是他决定修改。
之前,TT 为了整齐,把军事基地建成了矩形,而且如果两个微子发射器的连线平行于军事基地的一边,这
两个微子发射器之间就一定有微子能量传输线相连。
(*注:比如有 3 个微子发射器A(1,1)、B(1,3)、C(2,2),那么 A 和 B 之间有微子能量传输线相连,
A 和 B 不能传输到 C。*)
但是在微子能运输过程中发现,常常不能从一个微子发射器运抵另一个微子发射器。
为了可以从任何一个微子传输器能运抵其它任意一个微子传输器,而且能和原来的微子能量网同样整齐,
TT 决定遵循原来的规则,调动他的百万农奴新修建一些微子能量传输线和微子发射器。由于微子发射器的
造价比微子传输线高得多,所以 TT 决定忽略微子能量传输线的成本。
但是 TT 又不想花费不必要的钱,所以找到你为他计算最少需要建多少个微子发射器。
输入格式 Input Format
第一行三个正整数 n、m、p。(2<=n,m<=100000,表示军事基地的两边长;2<=p<=200000,表示微子
发射器的个数。)
接下来 p行,每行两个正整数数 Xi、 Yi(1<=Xi<=n 1<=Yi<=m),代表每个微子发射器在军事基地的位置。
(可能会由于疏漏,有些微子发射器重复)
输出格式 Output Format
样例:
输入:5 6 6
1 1
2 2
2 4
3 3
5 1
5 5
输出:
2
只有一行,为最少修建微子发射器的数量。
样例的一种方案:
#.....
|#-#..
|.#+..
|.|...
#-+-#.
#表示原有微子发射器,-、|表示微子能量传输线,+表示兴建的微子发射器。所以至少兴建 2 个微子发射
器。
分析
我们先这样考虑,如果对所有已知的节点进行染色的话,能染成同一种颜色的节点一定在同一个强连通分量中(内部连同),那么需要兴建的节点数就等于强连通分量数减一
我们来证明这个结论:对于任意一个节点它可以照顾到一行一列上的所有节点。也就是说,一个节点最多可以连接到4个强连通分量。如果一个兴建的节点只连接一个强连通分量,那么这个节点是毫无用处的。如果一个节点连接3个强连同分量,那么这3个强连通分量必有两个已经在一个强连通分量中。连接4个同理。只有当一个节点连接两个强连通分量时,才能让这两个原先不连通的分量相互连同。
这就类似于最小生成树,将兴建的节点看成边,原有的强连通分量看做节点,那么n个节点连成一颗生成树必然需要n-1个节点。
下面的问题就是如何染色。
如果用floodfill会很复杂,而且显然会超时。我们要考虑更加优秀的的算法。我们现在需要将在一个强连通分量中的原节点赋予同一个标识,并查集!
再加一个标记数组(n+m 表示某行或某列上是否有节点)。每读入一个节点我们就将其所在的行和列和并在一个集合中。这样就将一个强连同分量中的所有行和列合并在了同一个集合中。
最后,只需要枚举每行(列),如果该行(列)被标记过(在某个强连通分量中),那么找到它的根节点,累计总数并且标记当前强连通分量被访问过(应用并查集压缩路径后在同一个集合中的元素的祖先相同),只需标记其祖先即可。
var
f:array[1..400000] of longint;
v:array[1..400000] of boolean;
i,n,m,p,x,y,temp1,temp2,ans:longint;
function find(x:longint):longint;
begin
if f[x]=x then exit(x);
f[x]:=find(f[x]);
exit(f[x]);
end;
begin
assign(input,'wei.in');reset(input);
assign(output,'wei.out');rewrite(output);
readln(n,m,p);
for i:=1 to n+m do f[i]:=i;
for i:=1 to p do
begin
readln(x,y);
temp1:=find(x);
temp2:=find(y+n);
if temp1<>temp2 then
f[temp1]:=temp2;
v[x]:=true;
v[y+n]:=true;
end;
for i:=1 to n+m do
if v[i] then
begin
temp1:=find(i);
if v[temp1] then
begin
inc(ans);
v[temp1]:=false;
end;
end;
writeln(ans-1);
close(input);
close(output);
end.
反思
要先对题目分析,抽象其模型,再选取合适的数据结构解决问题,并查集应用不多但都很巧妙,可用来判断逻辑关系和集合关系