7-5 部落 (20分) HBU-DS

本文介绍了一种使用并查集解决部落统计问题的方法。通过输入社区内的小圈子信息,利用并查集进行数据处理,统计社区内的总人数及互不相交部落的数量,并判断任意两人是否属于同一部落。

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];
}

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值