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

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

显然本质就是求无向图的连通份量个数。而要求连通份量数,就是遍历图的过程。遍历完全部节点,须要调用遍历几回就是连通份量个数。好比题目中使用DFS,从节点1出发,能够遍历节点2,3,而要遍历完全部节点还需从节点4出发,再遍历一次,共遍历两次,所以连通份量数为2。实现代码以下:get

#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\n", sum);
    }
    return 0;
}

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

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

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

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

#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\n", sum);
    }
    return 0;
}

显然空间大大减小了,只须要O(n)的空间。效率

相关文章
相关标签/搜索