关于查并集也是浅浅的了解了一点,查并集是将一些不相交的集合合并,形成一条线或者形成一个散射图等。
大体上分为3部。
1、初始化
2、合并
3、查找
初始化就是将每一个点看成一个集合。
for(int i=1;i<=n;i++)
s[i]=i;
合并是把两个相关的点录入s[n]数组
void union_s(int x,int y)
{
int xx=find_s(x);
int yy=find_s(y);
if(xx!=yy)s[x]=y;
}
第三步查找就是给定一个数通过递归来找到他的根结点
int find_s(int n)
{
while(pre[n] != n)
n= s[n];
return n;
}
但是这种方法会导致路径过长,所以我们在查找的时候可以进行优化,把路径进行压缩,使他们都指向根结点。
int find_s(int n)
{
if(n!=s[n])s[n]=find_s(s[n]);
return s[n];
}
这么说有点浅显直接上题
有n个人一起吃饭,认识的人一桌(只要有一个认识的即可),例如:a和b认识,b和c认识,a/b/c就可以在一桌。试问需要几个桌子;
第一行输入n和m表示n个人和共有m组两两认识
第二行到第m+1行输入a和b两个数表示A和B两两认识
最终输出共有几个桌
分析:
这其实就是简单地查并集问题只要找到有几个根结点即可
代码:
#include <iostream>
#include<fstream>
#include <vector>
#include <utility>
#include <cstring>
#include <algorithm>
#include <map>
#include <queue>
#include <stack>
#include <cstdio>
#include <fstream>
#include <set>
#include<stdio.h>
#include<bits/stdc++.h>
#include <iomanip>
#include<cmath>
#define INF 0x7fffffff
#define inf 0x3f3f3f3f
#include<iostream>
using namespace std;
int n;
int s[1000010],a[100010]={0};
void inti(int n)
{
for(int i=1;i<=n;i++)
s[i]=i;
}
int find_s(int a)
{
if(s[a]==a) return a;
return s[a]=find_s(s[a]);
}
/* find_s函数查找每一个数的根结点并赋值为根结点的值 */
void union_s(int x,int y)
{
int xx=find_s(x);
int yy=find_s(y);
if(xx!=yy)s[xx]=yy;
}
int main()
{
int x,y,l;
cin>>n>>l;//输入n个人和l组关系
inti(n); //对每个人进行初始化,每个人都是自己的根结点
for(int i=1;i<=l;i++)
{
cin>>x>>y;
union_s(x,y); //将两个人的关系合并
}
int sum=0;
for(int i=1;i<=n;i++)
a[find_s(i)]=1; //查找这n个人的根结点,并将根结点赋值,不是根结点的不进行赋值
for(int i=1;i<=n;i++)
if(a[i])sum++;//判断根节点的个数从而判断需要几个桌子
cout<<sum<<endl;
return 0;
}
总结:
查并集就是来求数据之间关系的,固定的模板还算是比较简单和比较容易理解的。