从零起步看算法(第二十二天 5.14)
//并查集
1.基本操作
简单理解就是,比爸爸,换爸爸,收儿子的方法。
1.初始化>>查找>>合并
2.路径压缩
3.带权并查集
2.disjoint
树形的应用
#include <iostream>
using namespace std;
int father[110],n;
int dist[110],size[110];//dist 距离,//size 权重
void init(){
for(int i=1;i<=n;++i){
father[i]=i,dist[i]=0,size[i]=1;
}
}
int get(int x){
if(father[x]==x){
return x;
}
int y=father[x];
father[x]=get(y);//找到根节点
dist[x]+=dist[y];
return father[x];
}
void merge(int a,int b){
a=get(a);
b=get(b);
if(a!=b){
father[a]=b;
dist[a]=size[b];
size[b]+=size[a];//有几队
}
}
int main() {
n=10;
init();//初始化
merge(1,2);
merge(10,7);
merge(3,4);
merge(3,7);
get(1);
cout<<dist[1]+1<<endl;
get(3);
cout<<dist[3]+1<<endl;
return 0;
}
3.朋友
理解并查集的思想后,一切就没那么复杂了。
//朋友
#include<iostream>
#include<string>
using namespace std;
int father[5000+5];
void init(int n){//初始化
for(int i=1;i<=n;++i){
father[i]=i;
}
}
int get(int x){//找爸爸
if(father[x]==x){
return x;
}
int y=father[x];
father[x]=get(y);
return father[x];
}
void merge(int a,int b){//换爸爸
a=get(a);
b=get(b);
if(a!=b){
father[a]=b;
}
}
void is_friend(int a,int b){
if(get(a)==get(b))
{
cout<<"Yes"<<endl;
}
else cout<<"No"<<endl;
}
int main(){
int n,m,p;
cin>>n>>m>>p;
init(n+5);
while(m--){
int A1,B1;
cin>>A1>>B1;
merge(A1,B1);
}
while(p--){
int A2,B2;
cin>>A2>>B2;
is_friend(A2,B2);
}
return 0;
}
4.网络交友
<set>,<map>,并查集的 ,综合题
//网络交友
#include<iostream>
#include<map>
#include<set>
using namespace std;
int father[10000+10];
void init(int n){
for(int i=1;i<=n;i++)
father[i]=i;
}
int get(int x){
if(father[x]==x){
return x;
}
int y=father[x];
father[x]=get(y);
return father[x];
}
void merge(int x,int y){
int a=get(x);
int b=get(y);
if(a!=b){
father[a]=b;
}
}
int main(){
int n;
cin>>n;
set<string> se;
map<string ,int> ma;
int p=1;
init(n+10);
while(n--){
string a,b;
cin>>a>>b;
if(!se.count(a)){
se.insert(a);
ma[a]=p++;
}
if(!se.count(b)){
se.insert(b);
ma[b]=p++;
}
merge(ma[a],ma[b]);//并查集
int ans=0;
for(int i=1;i<p;i++){
if(get(i)==get(ma[b]))
ans++;
}
cout<<ans<<endl;
}
return 0;
}