没有使用图表可以有效解决方案?

时间:2012-10-28 21:58:04

标签: algorithm stack

列出了元组(i,j),每个元组(i,j)都会告诉您ij是朋友。友谊具有传染性,因此如果ij是朋友,jk是朋友,ik是朋友,即使如果元组(i,k)不存在。所以问题是,对于一组整数1到N,以及一个元组列表,如何有效地确定所有数字是否是彼此之间的朋友。

除非使用天真算法,否则可以设计一个有效的算法,而不使用图表?

此问题还有另一种变体,其中的问题是查找给定元组(m,n)是否为朋友。这可以使用堆栈来实现。

1 个答案:

答案 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()),请将一个组的主要成员指向另一个组的主要成员。