寒假第四次训练-并查集&生成树
A - How Many Tables
题目大意:招待客人需要把互相认识放在一桌,给定认识关系,问最少要多少桌
解题思路:并查集,求有多少根
AC代码:
#include <iostream>
#include <cstdio>
#include <string>
#include <algorithm>
#include <map>
#include <vector>
#include <cstring>
using namespace std;
#define MAXN 1005
int 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 20005
pair<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 100005
int 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");
}
}