// 递推 intfindFather(int x){ int a = x; // 保存起点值 while (x != father[x]) { // 寻找根结点 x = father[x]; } while (a != father[a]) { int z = a; a = father[a]; // 回溯父结点 father[z] = x; // 将原先的结点a的父亲改为根结点x } return x; }
// 递归 intfindFather(int x){ if (x == father[x]) return x; else { int F = findFather(father[x]); father[x] = F; return F; } }
至于集合个数的求解,需要用到本节最开始时讲解过的知识:“对同一个集合来说只存在一个根结点,且将其作为所属集合的标识”。因此可以开一个bool型数组 fag[N] 来记录每个结点是否作为某个集合的根结点,这样当处理完输入数据之后就可以遍历所有元素,令它所在集合的根结点的 flag 值设为 true。最后累加 flag 数组中的元素即可得到集合数目。
voidinit(int n){ for (int i = 1; i <= n; i++) father[i] = i; return; }
voidUnion(int a, int b){ int faA = findFather(a); int faB = findFather(b); if (faA != faB) father[faA] = father[faB]; return; }
intfindFather(int x){ int a = x; while (x != father[x]) x = father[x]; while (a != father[a]) { int z = a; a = father[a]; father[z] = x; } return x; }
intmain(){ int n, m, a, b; cin >> n >> m; father.resize(n + 1); isRoot.resize(n + 1, false); init(n); for (int i = 0; i < m; i++) { cin >> a >> b; Union(a, b); } for (int i = 1; i <= n; i++) isRoot[findFather(i)] = true; // 注意是findFather(i) int ans = 0; for (int i = 1; i <= n; i++) ans += isRoot[i]; cout << ans; return0; }
[1107] Social Clusters
题目
When register on a social network, you are always asked to specify your hobbies in order to find some potential friends with the same hobbies. A social cluster is a set of people who have some of their hobbies in common. You are supposed to find all the clusters.
Input Specification:
Each input file contains one test case. For each test case, the first line contains a positive integer , the total number of people in a social network. Hence the people are numbered from 1 to . Then lines follow, each gives the hobby list of a person in the format:
:
where is the number of hobbies, and is the index of the -th hobby, which is an integer in [1, 1000].
Output Specification:
For each case, print in one line the total number of clusters in the network. Then in the second line, print the numbers of people in the clusters in non-increasing order. The numbers must be separated by exactly one space, and there must be no extra space at the end of the line.
注意点与解析
判断两个人是好朋友的条件为他们有公共喜欢的活动,因此不妨开一个数组 course,其中 course[h] 用以记录任意一个喜欢活动 h 的人的编号,这样的话findFather(course[h]) 就是这个人所在的社交网络的根结点。于是,对当前读入的人的编号 i 和他喜欢的每一个活动 h,只需要合并 i 与 findFather(course[h]) 即可。
intfindFather(int x){ int a = x; while(x != father[x]) x = father[x]; while(a != father[a]) { int z = a; a = father[a]; father[z] = x; } return x; }
voidunion2(int a, int b){ int fa = findFather(a); int fb = findFather(b); if (fa != fb) father[fa] = fb; // a -> b return; }
intmain(){ int n, k, ans = 0; cin >> n; father.resize(n + 1); isRoot.resize(n + 1, false); vector<int> course(1001, 0);
for (int i = 1; i <= n; i++) father[i] = i; for (int i = 1; i <= n; i++) { scanf("%d:", &k); int a; for (int j = 0; j < k; j++) { cin >> a; if (course[a] == 0) course[a] = i; union2(i, findFather(course[a])); } } for (int i = 1; i <= n; i++) isRoot[findFather(i)]++; for (int i = 1; i <= n; i++) if (isRoot[i] != 0) ans++;
sort(isRoot.begin(), isRoot.end(), [&](int a, int b) { return a > b; }); cout << ans << endl; for (int i = 0; i < ans; i++) { cout << isRoot[i]; if (i != ans - 1) cout << " "; } return0; }
[1013] Battle Over Cities
题目
It is vitally important to have all the cities connected by highways in a war. If a city is occupied by the enemy, all the highways from/toward that city are closed. We must know immediately if we need to repair any other highways to keep the rest of the cities connected. Given the map of cities which have all the remaining highways marked, you are supposed to tell the number of highways need to be repaired, quickly.
For example, if we have 3 cities and 2 highways connecting - and -. Then if is occupied by the enemy, we must have 1 highway repaired, that is the highway -.
Input Specification:
Each input file contains one test case. Each case starts with a line containing 3 numbers , and , which are the total number of cities, the number of remaining highways, and the number of cities to be checked, respectively. Then lines follow, each describes a highway by 2 integers, which are the numbers of the cities the highway connects. The cities are numbered from 1 to . Finally there is a line containing numbers, which represent the cities we concern.
Output Specification:
For each of the K cities, output in a line the number of highways need to be repaired if that city is lost.
int n, m, k; vector<vector<int>> G; vector<bool> vis; vector<int> father;
intfindFather(int x){ int a = x; while (x != father[x]) x = father[x]; while (a != father[a]) { int z = a; a = father[a]; father[z] = x; } return x; }
voidUnion(int a, int b){ int faA = findFather(a); int faB = findFather(b); if (faA != faB) father[faA] = father[faB]; return; }
voidinit(){ for (int i = 1; i <= n; i++) { father[i] = i; vis[i] = false; } return; }
intmain(){ cin >> n >> m >> k; vis.resize(n + 1); father.resize(n + 1); G.resize(n + 1);
int a, b, cur; for (int i = 0; i < m; i++) { cin >> a >> b; G[a].push_back(b); G[b].push_back(a); } for (int i = 0; i < k; i++) { cin >> cur; init(); for (int v = 1; v <= n; v++) { for (auto u: G[v]) { if (v == cur || u == cur) continue; Union(v, u); } } int ans = 0; for (int j = 1; j <= n; j++) { if (j == cur) continue; int fa_j = findFather(j); if (vis[fa_j] == false) { ans++; vis[fa_j] = true; } } cout << ans - 1 << endl; } return0; }
[1021] Deepest Root
题目
A graph which is connected and acyclic can be considered a tree. The height of the tree depends on the selected root. Now you are supposed to find the root that results in a highest tree. Such a root is called the deepest root.
Input Specification:
Each input file contains one test case. For each case, the first line contains a positive integer which is the number of nodes, and hence the nodes are numbered from 1 to . Then lines follow, each describes an edge by given the two adjacent nodes’ numbers.
Output Specification:
For each test case, print each of the deepest roots in a line. If such a root is not unique, print them in increasing order of their numbers. In case that the given graph is not a tree, print Error: K components where K is the number of connected components in the graph.
注意点与解析
⾸先深度优先搜索判断它有⼏个连通分量。如果有多个,那就输出 Error: x components,如果只有⼀个,就两次深度优先搜索,先从⼀个结点dfs后保留最⾼⾼度拥有的结点们,然后从这些结点中的其中任意⼀个开始dfs得到最⾼⾼度的结点们,这两个结点集合的并集就是所求;