思路
说实话,这题细节挺多的。
首先题中说,有的人会疯狂加自己好友,这样我们对于一个朋友圈中已经出现的人,就没必要加了。
如果直接使用并查集,每次出现一个人我们就初始化一个人的父亲的话,这样对于朋友圈中只有自己的人,我们会判断错误,所以对于朋友,我们令朋友a不等于朋友b,这时我们才连接他们的朋友关系,否则它的父亲就是-1,这样查询的时候就可以很快了。
题中也没有说一个朋友圈中有人,所以我们如果每次读入的时候,就应该判断k是否为0,为真才读入一个人,然后继续读入。
输出的时候可以用unordered_map判断这个人有没有出现过。
还有就是对于递归的并查集的find函数这题如果不加inline就会堆栈溢出,加了inline之后就会优化代码结构,把递归改成循环,但是仅仅适用于代码行数小的情况。
不用递归也可以把find改成循环,不过记得修改这条链每个人的父亲,不然会超时。
代码
#include <bits/stdc++.h>
using namespace std;
const int maxn=1e6+10;
int pre[maxn];
//inline int find(int x) {
// if (pre[x]==x) {
// return x;
// }
// pre[x]=find(pre[x]);
//}
inline int find(int x) {
int root=x;
while (pre[x]!=x) {
x=pre[x];
}
int tmp;
while (pre[root]!=x) {
tmp=pre[root];
pre[root]=x;
root=tmp;
}
return x;
}
inline void unions(int x,int y) {
int fx=find(x);
int fy=find(y);
if (fx!=fy) {
pre[fx]=fy;
}
}
inline void init(int p) {
if (pre[p]==-1) {
pre[p]=p;
}
}
int main()
{
memset(pre,-1,sizeof(pre));
int n;
scanf("%d",&n);
int k;
while (n--) {
scanf("%d",&k);
unordered_map<int,int> cache;
int p;
int fa;
if (k) {
scanf("%d",&fa);
cache[fa]=1;
}
for (int i=1;i<k;i++) {
scanf("%d",&p);
if (!cache[p]) {
cache[p]=1;
init(fa);
init(p);
unions(fa,p);
}
}
}
int m;
int p;
int cnt=0;
scanf("%d",&m);
bool print=0;
unordered_map<int,int> cache;
for (int i=0;i<m;i++) {
scanf("%d",&p);
if (!cache[p]) {
cache[p]=1;
if (pre[p]==-1) {
if (!print) {
print=1;
}
else {
putchar(' ');
}
printf("%05d",p);
cnt=1;
}
}
}
if (!cnt) {
printf("No one is handsome");
}
putchar('
');
return 0;
}
/*
4
5 3 3 3 3 3
5 2 2 2 2 2
4 2 1 2 1
0
4
3 2 1 9999
*/