题目链接:http://codeforces.com/contest/1013/problem/D
题意:给你一个n*m的方格,然后再给你q个点(r,c),如果在这些方格中存在矩形的三个点,那么第四个点也可以得到,问你至少需要额外的多少个点,才能把表格填满。
思路:在做这题的时候一点思路都没有,唯一想到的就是暴力去做,但是会超时,想了挺久想不出来,就去看了看大佬的代码,发现竟然可以用并查集去做超级神奇,然后我自己试了几个样例都对,但我不会证明为什么会对,只能粗略地说一下:
当这一行或者这一列都不存在点的时候,你就必须在这一行或者这一列加一个点,然后分别隶属于两个根的点(两颗不同的树),需要额外的一个点把它们合并起来,最终所有的点都在一棵树中。
代码如下:
#include<iostream>
#include<stdlib.h>
#include<stdio.h>
#include<string.h>
#include<string>
#include<math.h>
#include<algorithm>
#include<functional>
#include<queue>
#include<stack>
#include<vector>
#include<set>
#include<unordered_map>
#define INF 0x3f3f3f3f
#define ll long long
#define ull unsigned long long
using namespace std;
#define MAXN 100010
int p[400005];
int find(int x)
{
if(p[x]==x)return x;
return p[x]=find(p[x]);
}
void join(int x,int y)
{
int fx=find(x);
int fy=find(y);
if(fx!=fy)
p[fx]=fy;
}
int main()
{
int n,m,q;
scanf("%d%d%d",&n,&m,&q);
for(int i=0;i<=n+m;i++)
p[i]=i;
while(q--)
{
int x,y;
scanf("%d%d",&x,&y);
join(x,y+n);
}
int ans=0;
for(int i=1;i<=n+m;i++)
if(find(i)==i)ans++;
printf("%d\n",ans-1);//减去最终那棵树的根
return 0;
}
还有一种dfs的做法,比较好理解一些
#include<iostream>
#include<stdlib.h>
#include<stdio.h>
#include<string.h>
#include<string>
#include<math.h>
#include<algorithm>
#include<functional>
#include<queue>
#include<stack>
#include<vector>
#include<set>
#include<unordered_map>
#define inf 0x3f3f3f3f
#define ll long long
#define ull unsigned long long
using namespace std;
#define MAXN 100010
vector<int> c[400005];
int vis[400005];
void dfs(int x)
{
if(vis[x]) return;
vis[x]=1;
for(int i=0; i<c[x].size(); i++) dfs(c[x][i]);
}
int main()
{
int n,m,q;
scanf("%d%d%d",&n,&m,&q);
memset(vis,0,sizeof(vis));
while(q--)
{
int x,y;
scanf("%d%d",&x,&y);
c[x].push_back(y+n);
c[y+n].push_back(x);
}
int ans=0;
for(int i=1;i<=n+m;i++) if(!vis[i]) dfs(i),ans++;
printf("%d\n",ans-1);
}