CF1013D Chemical table

题目链接:http://codeforces.com/contest/1013/problem/D

题目大意:

  给出一个 \(n \times m\) 的表格,表格上有一些初始点。若有这样的三个点:\((r_1, c_1), (r_1, c_2), (r_2, c_1)\),则由这三个点能生成出点 \((r_2, c_2)\)。现问在初始点的基础上最少添加多少个点,能使得初始点和添加的点及它们生成出来的点能填满整个表格。

知识点:  并查集

解题思路:

  可以将每一个点看成是将所在的行和列联系起来。如此一来,对于 \((r_1, c_1) + (r_1, c_2) + (r_2, c_1) \Rightarrow (r_2, c_2)\),我们可以理解为:因为 \(r_1\) 和 \(c_1\),\(r_1\) 和 \(c_2\),\(r_2\) 和 \(c_1\) 都相应地联系起来了,那么 \(r_2\) 和 \(c_2\) 也联系起来了。所以我们只要把所有的行和列都联系起来,生成出来的点就能填满整个表格。那么问题就转换成问最少建立多少联结,能将所有的行和列都联系起来。可以用并查集解决。

AC代码

 1 #include <bits/stdc++.h>
 2 using namespace std;
 3 typedef long long LL;
 4 #define lson l,m,rt<<1
 5 #define rson m+1,r,rt<<1|1
 6 const int MAXN=200000+5;
 7 const int INF=0x3f3f3f3f;
 8 const int MOD=1e9+7;
 9 
10 int fa[MAXN<<1];
11 int finds(int x){
12     if(fa[x]==x)    return x;
13     return fa[x]=finds(fa[x]);
14 }
15 int main(){
16     int r,c,n,m,q;
17     scanf("%d%d%d",&n,&m,&q);
18     for(int i=1;i<=n+m;i++) fa[i]=i;
19     for(int i=0;i<q;i++){
20         scanf("%d%d",&r,&c);
21         int f1=finds(r),f2=finds(c+n);
22         if(f1!=f2)  fa[f1]=f2;
23     }
24     int ans=0;
25     int root=finds(1);
26     for(int i=1;i<=n+m;i++){
27         int temp=finds(i);
28         if(temp!=root){
29             ans++;
30             fa[temp]=root;
31         }
32     }
33     printf("%d\n",ans);
34     return 0;
35 }

 

posted @ 2018-07-31 00:48  Blogggggg  阅读(289)  评论(0编辑  收藏  举报