在社交网络平台注册时,用户通常会输入自己的兴趣爱好,以便找到和自己兴趣相投的朋友。有部分兴趣相同的人们就形成了“社交集群”。现请你编写程序,找出所有的集群。
输入格式:
输入的第一行给出正整数N(<=1000),即社交网络中的用户总数(则用户从1到N编号)。随后N行,每行按下列格式列出每个人的兴趣爱好:
Ki: hi[1] hi[2] ... hi[Ki]
其中Ki(>0)是第i个人的兴趣的数量,hi[j]是第i个人的第j项兴趣的编号,编号范围为[1, 1000]内的整数。
输出格式:
首先在第一行输出整个网络中集群的数量,然后在第二行按非递增的顺序输出每个集群中用户的数量。数字间以1个空格分隔,行首尾不得有多余空格。
输入样例:8 3: 2 7 10 1: 4 2: 5 3 1: 4 1: 3 1: 4 4: 6 8 1 5 1: 4输出样例:
3 4 3 1
解题思路
想到两种,都实现了一下,都能AC
思路一:图的连通分支数。
这里求无向图的连通分支数用了有向图连通分支数的代码,原因是最近刚做了一道有向图连通性的题目,默了一遍代码巩固一下,上个题有向图的连通分支数代码有详细的注释,链接http://blog.csdn.net/ly59782/article/details/65442078,无向图的连通分支数很简单不再重写。主要说一下思路。
将兴趣与人连边,为了不混淆,人的编号是1~n兴趣的编号是n+1~2000。
然后求图的连通分支数,即为集群数。
思路二:并查集。
将每个人挂在他的兴趣下面,可重复挂,然后将每个兴趣下面的人做一个并查集,最后统计父亲节点的个数以及没个分支的人数。详见代码
代码1:统计图的连通分支数
#include <iostream>
#include <cstdio>
#include <map>
#include <cmath>
#include <string.h>
#include <algorithm>
#include <set>
#include <sstream>
#include <vector>
#include <queue>
#include <stack>
using namespace std;
const int maxn = 2000+10;
const int INF = 0x3f3f3f3f;
vector<int> G[maxn];
stack<int> s;
int pre[maxn];
int lowlink[maxn];
int sccno[maxn];
int dfsLock;
int sccCnt;
int ans[maxn];///第i个集群的人数
int n;///n个人,编号1到n
void dfs(int u){
pre[u] = lowlink[u] = ++dfsLock;
s.push(u);
for(int i = 0;i<G[u].size(); ++i){
int v = G[u][i];
if(!pre[v]){
dfs(v);
lowlink[u] = min(lowlink[u],lowlink[v]);
}
else if(!sccno[v]){
lowlink[u] = min(lowlink[u],pre[v]);
}
}
if(pre[u] == lowlink[u]){
sccCnt++;
while(1){
int x = s.top();s.pop();
if(x>=1 && x<=n) ans[sccCnt] ++;
if(x == u) break;
}
}
}
int main()
{
scanf("%d",&n);
for(int i = 1;i<=n;++i){
int m,t;
scanf("%d:",&m);
while(m>0){
m--;
scanf("%d",&t);
G[t+n].push_back(i);
G[i].push_back(t+n);///兴趣的编号为n+1~2000
}
}
for(int i = 1; i<=n; ++i){
if(!pre[i]) dfs(i);
}
sort(ans+1,ans+1+sccCnt);
printf("%d\n",sccCnt);
for(int i =sccCnt;i>0;--i){
printf("%d",ans[i]);
if(i!=1) printf(" ");
}
return 0;
}
代码2:并查集
#include <iostream>
#include <cstdio>
#include <vector>
#include <algorithm>
#define maxn 1010
using namespace std;
vector<int> G[maxn];
int f[maxn];
int fsize[maxn];
int findp(int x){
int xp = x;
while(xp!=f[xp]){
xp = f[xp];
}
f[x] = xp;
return xp;
}
int main()
{
int n;
scanf("%d",&n);
for(int i = 1;i<=n;++i){
int m,t;
scanf("%d:",&m);
for(int j = 0; j<m;++j){///编号为t的兴趣下面挂着对他感兴趣的人
scanf("%d",&t);
G[t].push_back(i);
}
}
///初始化
for(int i = 0;i<maxn;++i){
f[i] = i;
fsize[i] = 1;
}
for(int i = 1;i<maxn;++i){
if(G[i].size() == 0) continue;
int fa = findp(G[i][0]);
for(int j = 1; j<G[i].size();++j){
int fb = findp(G[i][j]);
if(fa != fb){
f[fb] = fa;
fsize[fa] += fsize[fb];
}
}
}
int cnt = 0;
vector<int> ans;
for(int i = 1;i<=n;++i){
if(f[i]==i)
{
cnt++;
ans.push_back(fsize[i]);
}
}
sort(ans.begin(),ans.end());
printf("%d\n",cnt);
for(int i = cnt-1; i>=0; --i){
printf("%d",ans[i]);
if(i!=0) printf(" ");
}
return 0;
}