• 小米2013校招笔试算法题-朋友圈个数


    题目描述:假如已知有n个人和m对好友关系(存于数字r)。如果两个人是直接或间接的好友(好友的好友的好友...),则认为他们属于同一个朋友圈,请写程序求出这n个人里一共有多少个朋友圈。
    假如:n = 5 , m = 3 , r = {{1 , 2} , {2 , 3} , {4 , 5}},表示有5个人,1和2是好友,2和3是好友,4和5是好友,则1、2、3属于一个朋友圈,4、5属于另一个朋友圈,结果为2个朋友圈。 最后请分析所写代码的时间、空间复杂度。评分会参考代码的正确性和效率。

    显然本质就是求无向图的连通分量个数。而要求连通分量数,就是遍历图的过程。遍历完所有节点,需要调用遍历几次就是连通分量个数。比如题目中使用DFS,从节点1出发,可以遍历节点2,3,而要遍历完所有节点还需从节点4出发,再遍历一次,共遍历两次,因此连通分量数为2。实现代码如下:

    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #define N 10000
    char map[N][N];
    char used[N];
    void dfs(int i, int n)
    {
        int j;
        used[i] = 1;
        for(j = 1; j <= n; j++) {
            if (map[i][j] && !used[j])
                dfs(j, n);
        }
    }
    /* 判断是否存在未访问节点
     * 若存在,则返回第一个未访问节点编号
     * 若不存在,则返回-1
     */
    int isVisitedAll(int n)
    {
        int i;
        for (i = 1; i <= n; i++)
            if (used[i] == 0)
                return i;
        return -1;
    }
    int main(int argc, char **argv)
    {
        int n, m;
        int a, b, i, sum, cur;
        while (scanf("%d%d", &n, &m) != EOF) {
            if (n == 0)
                break;
            memset(map, 0, sizeof(map));
            memset(used, 0, sizeof(used));
            sum = 0;
            for (i = 0; i < m; i++) {
                scanf("%d%d", &a, &b);
                map[a][b] = map[b][a] = 1;
            }
            while((cur = isVisitedAll(n)) != -1) {
                sum++;
                dfs(cur, n);
            }
            printf("%d
    ", sum);
        }
        return 0;
    }
    

    暂且不说时间复杂度吧,空间复杂度就足够吓人了。首先需要一个表示图的01矩阵,大小为O(n2), 还需要记录是否节点是否已经被访问,需要大小为O(n)的空间。

    换一种思路,其实根据题目朋友圈,我们就应该想到每一个圈其实就是一个集合,存在关系的,归为一个集合中,最后即需要求有多少个不相交的集合即有多少个圈子。

    由此不难想出,这其实就是并查集。

    想到了并查集,不难写出代码:

    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #define N 100000
    int father[N];
    void init(int n)
    {
        int i;
        for (i = 1; i <= n; i++)
            father[i] = i;
    }
    int getFather(int v)
    {
        if (father[v] == v)
            return v;
        else {
     
            father[v] = getFather(father[v]);
            return father[v];
        }
    }
    void merge(int x, int y)
    {
        int fx = getFather(x);
        int fy = getFather(y);
        if (fx < fy)
            father[fx] = fy;
        else
            father[fy] = fx;
    }
    int same(int x, int y)
    {
        return getFather(x) == getFather(y);
    }
    int main(int argc, char **argv)
    {
        int n, m;
        int a, b;
        int i;
        int sum;
        while (scanf("%d%d", &n, &m) != EOF) {
     
            if (n == 0)
                break;
            init(n);
            sum = 0;
            for (i = 1; i <= m; i++) {
                scanf("%d%d", &a, &b);
                merge(a, b);
            }
            for (i = 1; i <= n; i++) {
                if (getFather(i) == i)
                    sum++;
            }
            printf("%d
    ", sum);
        }
        return 0;
    }
    

    显然空间大大减少了,只需要O(n)的空间。

  • 相关阅读:
    D. Constructing the Array
    B. Navigation System
    B. Dreamoon Likes Sequences
    A. Linova and Kingdom
    G. Special Permutation
    B. Xenia and Colorful Gems
    Firetrucks Are Red
    java getInstance()的使用
    java 静态代理和动态代理
    java 类加载机制和反射机制
  • 原文地址:https://www.cnblogs.com/int32bit/p/5314191.html
Copyright © 2020-2023  润新知