列出了元组(i,j)
,每个元组(i,j)
都会告诉您i
和j
是朋友。友谊具有传染性,因此如果i
和j
是朋友,j
和k
是朋友,i
和k
是朋友,即使如果元组(i,k)
不存在。所以问题是,对于一组整数1到N,以及一个元组列表,如何有效地确定所有数字是否是彼此之间的朋友。
除非使用天真算法,否则可以设计一个有效的算法,而不使用图表?
此问题还有另一种变体,其中的问题是查找给定元组(m,n)
是否为朋友。这可以使用堆栈来实现。
答案 0 :(得分:2)
我已经学会了一种通过去除非常适用的墙来制作迷宫的算法。
int friendGroups[N];
// initially, all numbers are in a "forever alone" group.
for(i = 0; i < N; i++) {
friendGroups[i] = i;
}
int findFriendGroup(int p) {
int g = friendGroups[p];
if (g != p) {
g = friendGroups[p] = findFriendGroup(g);
}
return g;
}
void addFriendship(int i, int j) {
friendGroup[findFriendGroup(i)] = findFriendGroup(j);
}
int areFriends(int i, int j) {
return (findFriendGroup(i) == findFriendGroup(j));
}
findFriendGroup()
看起来效率可能很低,但每次调用都渐近花费O(A ^( - 1)(N))其中A ^( - 1)是逆Ackermann函数,它非常接近O(1 )这不值得担心。
int singleFriendGroup() {
int g = findFriendGroup(0);
int i;
for(i = 1; i < N; i++) {
if (findFriendGroup(i) != g) {
return 0;
}
}
return 1;
}
每个人都“指向”另一个人或他自己。每个朋友组都有一个指向自己的主要成员(friendGroups[i] == i
)。 findFriendGroup()
跟随点链以找到组的主要成员,并且在返回的路上使链中的每个人直接指向主要成员。要统一两个组(addFriendship()
),请将一个组的主要成员指向另一个组的主要成员。