By Jalan
文章目录
知识工具需求
数学
数据结构和算法
- 并查集
语言
题干
社会集是一群喷人有相同的兴趣,你要找出所有的社会集
时间给了1200ms
输入条件
N<=1000网中的总人数,
接下来是1-N的N行格式是:
K:H1 H2…
K是兴趣数量,后面是hi是第i个兴趣i[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
题解
第一次(没用并查集)
这个很好理解…因为时间给的很充裕,一般pta给1200ms加上<=1000这种,基本就是你随便玩吧…
思路
- 输入
- 依据当前的节点遍历相关节点,所有的兴趣都加到hashlist里,直到相关节点不再增加.(证明这种兴趣组不能再拓展)
- 排序
- 输出
预期时间复杂度
编写用时
30分钟
代码
CPP
#include <bits/stdc++.h>
#include <stdio.h>
#include <vector>
using namespace std;
int n;
vector<vector<int>> hobbies;
vector<bool> known;
vector<int> cluster;
int main(int argc, char const *argv[])
{
//1
scanf("%d", &n);
hobbies.resize(n + 1);
for (int i = 1, temp; i < n + 1; i++)
{
scanf("%d:", &temp);
for (int j = 0, temp2; j < temp; j++)
{
scanf("%d", &temp2);
hobbies[i].push_back(temp2);
}
}
//2
known.resize(n + 1);
cluster.resize(n + 1);
int clusterCounter = -1;
for (int i = 1; i < n + 1; i++)
{
if (known[i] == false)
{
++clusterCounter;
vector<int> hashList(1001);
vector<int> clusterIndex;
int originSize = 0;
for (int j = 0; j < hobbies[i].size(); j++)
{
hashList[hobbies[i][j]]++;
}
for (int j = i; j < n + 1; j++)
{
if (known[j] == false)
{
for (int k = 0; k < hobbies[j].size(); k++)
{
if (hashList[hobbies[j][k]])
{
known[j] = true;
clusterIndex.push_back(j);
break;
}
}
}
}
int finalSize = clusterIndex.size();
while (finalSize != originSize)
{
originSize = finalSize;
//把本次所有兴趣加到hashList里.
for (int j = 0; j < finalSize; j++)
{
for (int k = 0; k < hobbies[clusterIndex[j]].size(); k++)
{
hashList[hobbies[clusterIndex[j]][k]]++;
}
}
//遍历一次把兴趣一致的加进来
for (int j = 1; j < n + 1; j++)
{
if (known[j] == false)
{
for (int k = 0; k < hobbies[j].size(); k++)
{
if (hashList[hobbies[j][k]])
{
known[j] = true;
clusterIndex.push_back(j);
break;
}
}
}
}
finalSize=clusterIndex.size();
}
cluster[clusterCounter]=finalSize;
}
}
//3
sort(cluster.begin(),cluster.begin()+clusterCounter+1);
//4
printf("%d\n", clusterCounter+1);
for (int i = clusterCounter; i >=0; i--)
{
printf("%d%c", cluster[i], i == 0? '\n' : ' ');
}
return 0;
}
运行用时
第二次(并查集)
思路
首先得明确,在这个并查集里,用于建树的点(就是定点)指的是人的编号,集合之间的联系(边)则抽象成了集合的兴趣直接是否有重复,所以我们可以遍历兴趣建立边.
- 输入
- 遍历人的兴趣建立边
- 遍历边建立并查集树
- 遍历树,用map对根做统计
- 把map里的数导到vector里排序
- 输出
预期时间复杂度
编写用时
30分钟
代码
CPP
#include <vector>
using namespace std;
int n;
vector<vector<int>> hobbies;
typedef struct edge
{
int x;
int y;
} edge;
vector<edge> edges;
int findRoot(int vertex, vector<int> &parent)
{
int temp = vertex;
while (parent[vertex] != 0)
{
vertex = parent[vertex];
} //循环结束后vertex是根结点编号
while (parent[temp] != 0)
{
int temp2 = temp;
temp = parent[temp];
parent[temp2] = vertex;
} //把路上的节点都梳理到根结点下方
return vertex;
}
int unionVertex(int va, int vb, vector<int> &parent)
{
int vaRoot = findRoot(va, parent);
int vbRoot = findRoot(vb, parent);
if (vaRoot == vbRoot)
{
}
else
{
parent[vaRoot] = vbRoot;
}
return 0;
}
int main(int argc, char const *argv[])
{
//1
scanf("%d", &n);
hobbies.resize(n + 1);
for (int i = 1, temp; i < n + 1; i++)
{
scanf("%d:", &temp);
for (int j = 0, temp2; j < temp; j++)
{
scanf("%d", &temp2);
hobbies[i].push_back(temp2);
}
}
//2
for (int i = 1; i < n + 1; i++)
{
vector<int> hashList(1001);
for (int j = 0; j < hobbies[i].size(); j++)
{
hashList[hobbies[i][j]]++;
}
for (int j = i + 1; j < n + 1; j++)
{
for (int k = 0; k < hobbies[j].size(); k++)
{
if (hashList[hobbies[j][k]])
{
edges.push_back({i, j});
break;
}
}
}
}
//3
vector<int> parent(n + 1); //0代表不存在
for (int l = 0; l < edges.size(); l++)
{
int va=edges[l].x;
int vb=edges[l].y;
unionVertex(va, vb,parent);
}
//4
unordered_map<int,int> m;
for (int i = 1; i < n+1; i++)
{
int root=findRoot(i, parent);
m[root]++;
}
//5
vector<int> result;
for (auto &&i : m)
{
result.push_back(i.second);
}
sort(result.begin(),result.end());
//6
printf("%d\n",result.size());
for (int i = (int)result.size() - 1; i >= 0; i--)
{
printf("%d",result[i]);
if (i!=0)
{
printf(" ");
}
}
return 0;
}
运行用时
结尾
看在我写了这么多注释的份上可以给我点个赞嘛,求求惹=]砰砰砰,给我加点写下去的油呀@.@
也欢迎关注我的CSDN账号呀,接下来两个月我应该会按这个格式更新所有的PTA甲级题目
**开心code每一天**