并查集模版
void init(){
for(int i=1;i<=n;i++){
f[i]=i;
}
}
int Find(int x){
if(f[x]==x){
return x;
}
return f[x]=Find(f[x]);
}
void Union(int x,int y){
x=Find(x);
y=Find(y);
f[x]=y;
}
亲戚
题目描述
若某个家族人员过于庞大,要判断两个是否是亲戚,确实还很不容易,现在给出某个亲戚关系图,求任意给出的两个人是否具有亲戚关系。
规定:x和y是亲戚,y和z是亲戚,那么x和z也是亲戚。如果x,y是亲戚,那么x的亲戚都是y的亲戚,y的亲戚也都是x的亲戚。
输入描述
第一行:三个整数n,m,p,(n<=5000,m<=5000,p<=5000),分别表示有n个人,m个亲戚关系,询问p对亲戚关系。
以下m行:每行两个数Mi,Mj,1<=Mi,Mj<=N,表示Mi和Mj具有亲戚关系。
接下来p行:每行两个数Pi,Pj,询问Pi和Pj是否具有亲戚关系。
输出描述
P行,每行一个’Yes’或’No’。表示第i个询问的答案为“具有”或“不具有”亲戚关系。
#include<bits/stdc++.h>
using namespace std;
int n,m,p,x,y;
int f[50005];
void init(){
for(int i=1;i<=n;i++){
f[i]=i;
}
}
int Find(int x){
if(f[x]==x){
return x;
}
return f[x]=Find(f[x]);
}
void Union(int x,int y){
x=Find(x);
y=Find(y);
f[x]=y;
}
int main(){
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
cin>>n>>m>>p;
init();
for(int i=1;i<=m;i++){
cin>>x>>y;
Union(x,y);
}
for(int i=1;i<=p;i++){
cin>>x>>y;
if(Find(x)==Find(y)){
cout<<"Yes"<<"\n";
}
else{
cout<<"No"<<"\n";
}
}
return 0;
}
选学霸
题目描述
老师想从n名学生中选m人当学霸,但有k对人实力相当,如果实力相当的人中,一部分被选上,另一部分没有,同学们就会抗议。所以老师想请你帮他求出他该选多少学霸,才能既不让同学们抗议,又与原来的m尽可能接近。
输入描述
第一行,三个正整数n,m,k。
第2至第k行,每行2个数,表示一对实力相当的人的编号(编号为1,2,…,n)。
输出描述
一行,表示既不让同学们抗议,又与原来的m尽可能接近的选出学霸的数目。
如果有两种方案与m的差的绝对值相等,选较小的一种。
#include<bits/stdc++.h>
using namespace std;
int n,m,k,x,y;
int f[200005];
int num[200005];
int cnt,a[200005];
int dp[400005];
int minn=40001,ans;
void init(){
for(int i=1;i<=n;i++){
f[i]=i;
num[i]=1;
}
}
int Find(int x){
if(f[x]==x){
return x;
}
return f[x]=Find(f[x]);
}
void Union(int x,int y){
x=Find(x);
y=Find(y);
if(x==y){
return;
}
f[x]=y;
num[y]+=num[x];
}
int main(){
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
cin>>n>>m>>k;
init();
for(int i=1;i<=k;i++){
cin>>x>>y;
Union(x,y);
}
for(int i=1;i<=n;i++){
if(f[i]==i){
a[++cnt]=num[i];
}
}
for(int i=1;i<=cnt;i++){
for(int j=2*m;j>=a[i];j--){
dp[j]=max(dp[j],dp[j-a[i]]+a[i]);
}
}
for(int i=1;i<=2*m;i++){
if(abs(dp[i]-m)<minn){
minn=abs(dp[i]-m);
ans=dp[i];
}
}
cout<<ans;
return 0;
}
带权并查集
void init(){
for(int i=1;i<=n;i++){
f[i]=i;
dis[i]=1;
}
}
int Find(int x){
if(f[x]==x){
return x;
}
int root=Find(f[x]);
return f[x]=root;
}
void Union(int x,int y){
int fx=Find(x);
int fy=Find(y);
if(fx==fy){
return;
}
f[fx]=fy;
dis[y]=dis[x]+1;//按题目要求变化
}