7-5 部落 (20分)
在一个社区里,每个人都有自己的小圈子,还可能同时属于很多不同的朋友圈。我们认为朋友的朋友都算在一个部落里,于是要请你统计一下,在一个给定社区中,到底有多少个互不相交的部落?并且检查任意两个人是否属于同一个部落。
输入格式:
输入在第一行给出一个正整数N(≤104),是已知小圈子的个数。随后N行,每行按下列格式给出一个小圈子里的人:
K P[1] P[2] ⋯ P[K]
其中K是小圈子里的人数,P[i](i=1,⋯,K)是小圈子里每个人的编号。这里所有人的编号从1开始连续编号,最大编号不会超过104。
之后一行给出一个非负整数Q(≤104),是查询次数。随后Q行,每行给出一对被查询的人的编号。
输出格式:
首先在一行中输出这个社区的总人数、以及互不相交的部落的个数。随后对每一次查询,如果他们属于同一个部落,则在一行中输出Y,否则输出N。
输入样例:
4
3 10 1 2
2 3 4
4 1 5 7 8
3 9 6 4
2
10 5
3 7
输出样例:
10 2
Y
N
~
我先是想用 图的知识,(刚学了嘛),就是把这个以图的方式存下来,遍历可以得到连通分量,遍历也可以得到俩点是否相通。今天上午实验课 写了好久好久,但是遇到了一个很离谱的错误:alg没有申请空间,导致我找了好久!
然后中午在宿舍发现错误之后,malloc了一下,就能运行了!(还是很激动的)(doge)
但是还是有一个点超时。
后来查了一下,是什么 并查集 问题。
如果采用最简单的 并查集 ,那个点还是过不了,下面是什么 路径压缩(就是把每个非代表元素 连到了代表元素上)
代码_并查集 _路径压缩
#include <iostream>
using namespace std;
int find(int x);
void merge(int x, int y);
void init();
int fa[10001];
int main()
{
init();
int max = 0;
int N;
cin >> N;
while (N--)
{
int k;
cin >> k;
int x;
cin >> x;
if (x > max)
max = x;
for (int i = 1; i < k; ++i)
{
int cur;
cin >> cur;
if (cur > max)
max = cur;
merge(x, cur);
}
}
printf("%d ", max);
int cnt = 0;
for (int i = 1; i <= max; ++i)
{
if (i == find(i))
cnt++;
}
printf("%d\n", cnt);
cin >> N;
int a, b;
while (N--)
{
cin >> a >> b;
if (find(a) == find(b))
printf("Y\n");
else
printf("N\n");
}
}
int find(int x)
{
if (fa[x] == x)
return x;
else
{
fa[x] = find(fa[x]);
return find(fa[x]);
}
}
void merge(int x, int y)
{
fa[find(y)] = find(x);
}
void init()
{
for (int i = 1; i <= 10000; ++i)
fa[i] = i;
}
代码_ DFS_ 超时了
#include <iostream>
#include <vector>
using namespace std;
typedef struct ENode *PtrToENode;
struct ENode
{
int data;
ENode *next;
};
struct VNode
{
int data;
ENode *firstEdge;
};
typedef struct GraphNode *ALG;
struct GraphNode
{
VNode AdjList[10001];
int vsum;
};
int FindBranchNum();
bool Visited[10001];
void DFS(int v);
int DFSTraverseAL();
bool isSameBranch(int i, int j);
ALG alg = (ALG)malloc(sizeof(GraphNode));
int main()
{
int N;
cin >> N;
int num = 0;
while (N--)
{
int k;
cin >> k;
vector<int> v(k);
for (int i = 0; i < k; ++i)
{
cin >> v[i];
if (v[i] > num)
num = v[i];
}
for (int i = 0; i < k - 1; ++i)
for (int j = i + 1; j < k; ++j)
{
// v[i] v[j] 互相添加到 v[j] v[i] 的邻接表里
//v[i] li + v[j]
PtrToENode enode = (PtrToENode)malloc(sizeof(ENode));
enode->data = v[j];
enode->next = alg->AdjList[v[i]].firstEdge;
alg->AdjList[v[i]].firstEdge = enode;
//v[j] li + v[i]
enode = (PtrToENode)malloc(sizeof(ENode));
enode->data = v[i];
enode->next = alg->AdjList[v[j]].firstEdge;
alg->AdjList[v[j]].firstEdge = enode;
}
alg->vsum = num;
//alg 从1开始
//alg 创建完成
//输出
}
cout << num << " ";
//dfs 找连通分量的个数
cout << FindBranchNum() << endl;
cin >> N;
while (N--)
{
int i, j;
cin >> i >> j;
if (isSameBranch(i, j))
cout << "Y\n";
else
cout << "N\n";
}
}
int FindBranchNum()
{
return DFSTraverseAL();
}
void DFS(int v)
{
//从顶点v开始
Visited[v] = 1;
for (PtrToENode i = alg->AdjList[v].firstEdge; i != NULL; i = i->next)
{
// 这个循环是v的所有邻接边
if (!Visited[i->data]) //如果v还没有访问过
DFS(i->data);
}
}
int DFSTraverseAL()
{
int cnt = 0;
for (int i = 1; i <= alg->vsum; ++i)
{
if (!Visited[i])
{
DFS(i);
cnt++;
}
}
return cnt;
}
bool isSameBranch(int i, int j)
{
for (int i = 0; i <= alg->vsum; ++i)
Visited[i] = 0;
DFS(i);
return Visited[j];
}
本文介绍了一种使用并查集解决部落统计问题的方法。通过输入社区内的小圈子信息,利用并查集进行数据处理,统计社区内的总人数及互不相交部落的数量,并判断任意两人是否属于同一部落。
1916

被折叠的 条评论
为什么被折叠?



