題目描述:假如已知有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)的空間。效率