寒假第四次训练-并查集&生成树
A - How Many Tables
题目大意:招待客人需要把互相认识放在一桌,给定认识关系,问最少要多少桌
解题思路:并查集,求有多少根
AC代码:
#include <iostream>#include <cstdio>#include <string>#include <algorithm>#include <map>#include <vector>#include <cstring>using namespace std;#define MAXN 1005int par_[MAXN],rank_[MAXN];bool hash_[MAXN];void init_(int n){ for (int i=0;i<=n;i++) { par_[i]=i; rank_[i]=0; }}int find_(int x){ if (par_[x]==x) return x; else return par_[x]=find_(par_[x]);}void unite_(int x,int y){ x=find_(x); y=find_(y); if (x==y) return; if (rank_[x]<rank_[y]) { par_[x]=y; } else { par_[y]=x; if (rank_[x]==rank_[y]) rank_[x]++; }}int main(){ int t,a,b,m,n,count_; scanf("%d",&t); while(t--) { count_=0; fill(hash_,hash_+MAXN,true); scanf("%d%d",&n,&m); init_(n); for (int i=0;i<m;i++) { scanf("%d%d",&a,&b); unite_(a,b); } for (int i=1;i<=n;i++) { par_[i]=find_(i); if (hash_[par_[i]]) { count_++; hash_[par_[i]]=false; } } printf("%d\n",count_); }}
B - Corporative Network
题目大意:有n个互相独立的通信中心,有两种指令E和I,I a b表示将a中心连接到b中心,a与b之间距离为|a-b|,于是只剩下新的b中心,E a表示查询a到与之相连的中心的距离
解题思路:并查集,合并时将a并入b所在的集合
AC代码:
#include <iostream>#include <cstdio>#include <string>#include <algorithm>#include <map>#include <vector>#include <cstring>using namespace std;#define MAXN 20005pair<int,int> par_[MAXN];void init_(int n){ for (int i=0; i<=n; i++) { par_[i].first=i; par_[i].second=0; }}int find_(int x){ if (par_[x].first==x) return x; else { int parent=find_(par_[x].first); par_[x].second+=par_[par_[x].first].second; par_[x].first=parent; return parent; }}void unite_(int x,int y){ par_[x].first=y; par_[x].second+=abs(x-y)%1000;}int main(){ int t,a,b,n; char ch; scanf("%d",&t); while(t--) { scanf("%d",&n); init_(n); while (getchar(),(ch=getchar())!='O') { if (ch=='I') { scanf("%d%d",&a,&b); unite_(a,b); } if (ch=='E') { scanf("%d",&a); find_(a); printf("%d\n",par_[a].second); } } }}
C - 卿学姐与诡异村庄
题目大意:村庄有n人,村民有好有坏,好人说真话,坏人说假话,第i人会说某个人是好人或者坏人,问是否存在某个好人坏人的分类使得所有质控都被满足
解题思路:并查集分为两段好人n人坏人n人,i说ai为好人则i与ai要么都为好人要么都为坏人,所以合并i与ai,i+n与ai+n,i说ai为坏人则i好ai坏或者i坏ai好,合并i与ai+n还有i+n与ai。若存在合理分类那么对于任意i,i与i+n是相反的。
AC代码:
#include <iostream>#include <cstdio>#include <string>#include <algorithm>#include <map>#include <vector>#include <cstring>using namespace std;#define MAXN 100005int par[MAXN<<1],rank_[MAXN<<1];//pair<int,int> a[MAXN];void init_(int n){ for (int i=0; i<=n; i++) { par[i]=i; rank_[i]=0; }}int find_(int n){ if (par[n]==n) return n; else return par[n]=find_(par[n]);}bool same(int x,int y){ return find_(x)==find_(y);}void unite_(int x,int y){ int m=find_(x),n=find_(y); if (m==n) return; if (rank_[m]<rank_[n]) par[m]=n; else { par[n]=m; if (rank_[m]==rank_[n]) rank_[m]++; }}int main(){ int t,a,b,n,ai,flag=0; while(~scanf("%d",&n)) { flag=0; init_(n<<1); for (int i=1; i<=n; i++) { scanf("%d%d",&ai,&t); if (t==1) { unite_(i,ai); unite_(i+n,ai+n); } if (t==2) { unite_(i,ai+n); unite_(i+n,ai); } } for (int i=1; i<=n; i++) { if (find_(i)==find_(i+n)) { flag=1; printf("One face meng bi\n"); break; } } if (flag==0) printf("Time to show my power\n"); }}