C123【模板】扩展域并查集 P1892 [BOI2003] 团伙

C123【模板】扩展域并查集 P1892 [BOI2003] 团伙_哔哩哔哩_bilibili

 

P1892 [BalticOI 2003] 团伙 - 洛谷

题目:所有人之间有两种关系:朋友和敌人。给 n 个人,m个关系,求最多的团体数。


种类并查集:维护点的连通性和传递性。
扩展成两个域:朋友域(1~n)和敌人域(n+1~2n)。
若是朋友,合并a与b。
若是敌人,合并a与b的敌人,合并b与a的敌人。
统计根的个数即答案。

// 扩展域并查集 
#include<bits/stdc++.h>
using namespace std;

int n,m,ans;
int fa[2005];

int find(int x){
  return fa[x]==x?x:fa[x]=find(fa[x]);
}
void unite(int x,int y){
  fa[find(y)]=find(x);
}
int main(){
  cin>>n>>m;
  for(int i=1;i<=2*n;i++) fa[i]=i;
  for(int i=1,a,b;i<=m;i++){
    char ch; cin>>ch>>a>>b;
    if(ch=='F') unite(a,b); //若是朋友,合并a与b
    else{ //若是敌人,合并a与b的敌人,合并b与a的敌人
      unite(a,b+n); unite(b,a+n);
    }
  }
  for(int i=1;i<=n;i++)if(i==fa[i])ans++;
  cout<<ans;
}

 

P1525 [NOIP 2010 提高组] 关押罪犯 - 洛谷

// 扩展域并查集 
#include<bits/stdc++.h>
using namespace std;

struct E{
  int a,b,c;
  bool operator<(const E &t)const{
    return c>t.c;
  }
}e[100005];
int n,m,fa[40005];

int find(int x){
  return fa[x]==x?x:fa[x]=find(fa[x]);
}
void unite(int x,int y){
  fa[find(y)]=find(x);
}
int main(){
  cin>>n>>m;
  for(int i=1;i<=m;i++)cin>>e[i].a>>e[i].b>>e[i].c;
  sort(e+1,e+m+1); //按影响力降序
  for(int i=1;i<=n*2;i++) fa[i]=i;
  for(int i=1; i<=m; i++){ //贪心处理影响力大的
    int a=e[i].a,b=e[i].b;
    if(find(a)==find(b)){ //共集则发生冲突
      cout<<e[i].c; return 0;
    }
    unite(a,b+n); unite(b,a+n); //a,b分投集合
  }
  cout<<0;
}

 

posted @ 2024-05-20 21:26  董晓  阅读(514)  评论(0)    收藏  举报