标签:its pac 基础上 print can type style get 一个
题目链接: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 }
标签:its pac 基础上 print can type style get 一个
原文地址:https://www.cnblogs.com/Blogggggg/p/9393682.html