在无向图中查找所有非重叠循环

时间:2016-06-23 09:20:49

标签: ios objective-c algorithm graph cycle

我需要在无向图上找到所有简单的非重叠循环。为了找到所有现有周期,我在这里找到了算法的Objective-C版本:

Finding all cycles in undirected graphs

@interface HSValue : NSObject
@property (nonatomic, assign) CGPoint point;
@end
@implementation HSValue
@end


@interface CyclesFinder ()
@property (nonatomic, strong) NSMutableArray <NSArray<HSValue *>*> *cycles;
@property (nonatomic, strong) NSArray <NSArray<HSValue*>*> *edges;
@end

@implementation CyclesFinder

-(void)findCyclesInGraph:(NSArray <NSArray<HSValue*>*> *)edges {
   self.edges = edges;
   for (NSInteger i=0; i < self.edges.count; i++) {
        for (NSInteger j=0; j < self.edges[i].count; j++) {
            [self findNewCycles:@[self.edges[i][j]]];
        }
    }
}

-(void)findNewCycles:(NSArray <HSValue *> *)path {

    HSValue *startNode = path[0];
    HSValue *nextNode;
    NSArray <HSValue *> *sub;

    for (NSInteger i=0; i < self.edges.count; i++) {
        NSArray <HSValue *> *edge = self.edges[i];
        if ([edge containsObject:startNode]) {
            if ([edge[0] isEqual:startNode]) {
                nextNode = edge[1];
            }
            else {
                nextNode = edge[0];
            }
        }
        else {
            nextNode = nil;
        }

        if (![path containsObject:nextNode] && nextNode) {
            sub = @[nextNode];
            sub = [sub arrayByAddingObjectsFromArray:path];
            [self findNewCycles:sub];
        }
        else if (path.count > 2 && [nextNode isEqual:path.lastObject]) {
            if (![self cycleExist:path]) {
                [self.cycles addObject:path];
                break;
            }
        }
    }
}

-(BOOL)cycleExist:(NSArray <HSValue*> *)path {
    path = [path sortedArrayUsingSelector:@selector(compare:)];
    for (NSInteger i=0; i < self.cycles.count; i++) {
        NSArray <HSValue *> *cycle = [self.cycles[i] sortedArrayUsingSelector:@selector(compare:)];
        if ([cycle isEqualToArray:path]) {
            return TRUE;
        }
    }

    return FALSE;
}

上面的算法工作正常(即使效率不高),它可以从附图中的图表中找到所有可能的周期(请参见下图):

A-B-H-G-F-D-E-A(有效)

B-C-I-H-B(有效)

G-H-I-L-K-G(有效)

F-G-K-J-F(有效)

F-G-H-I-L-K-J-F(无效)

A-B-C-I-H-G-F-D-E-A(无效)

A-B-C-I-L-K-J-F-D-E-A(无效)

A-B-C-I-H-G - K-J-F-D-E-A(无效)

A-B-H-I-L-K-G-F-D-E-A(无效)

A-B-H-G-K-J-F-D-E-A(无效)

A-B-C-I-L-K-G-F-D-E-A(无效)

B-C-I-L-K-G-H-B(无效)

B-C-I-L-K-J-F-G-H-B(无效)

然而,当我运行上述算法时,我想最终只得到我在左侧示例中用彩色多边形突出显示的周期。我不想要的是像右边那样的循环。

enter image description here

我的第一个想法是重叠周期将是一个包含来自任何其他周期的所有点的周期,但这并非总是如此。有人能指出我正确的方向吗?是否有可能修改上述算法,以便它只找到非重叠的周期,或者如果不能找到所有周期来过滤它们后我应该做什么?

2 个答案:

答案 0 :(得分:2)

在无向图本身中没有足够的信息来确定哪个周期是哪个。例如,考虑以下2个图表产生相同的无向图:

A-----B      E-------------F
|     |       \           /
C-----D        \ A-----B /
|     |         \|     |/
E-----F          C-----D

但是对于左侧的图表,您需要循环ABDCA和CDFEC,而对于右侧的图表,您需要循环ABDCA和EFDBACE。因此,从图中推断出的无向图是不够的 - 您需要以某种方式合并原始图中的空间信息。

答案 1 :(得分:0)

我正在处理同样的问题,很多评论都很有用,特别是评论说每条边都有一个区域。因此,你可以说每条边都有一个&#34;左边区域&#34;和一个正确的区域&#34;。

您可以按任何顺序将所有图形边添加到队列中。窥视第一个边缘,选择靠近原点的顶点。移动到逆时针最多的邻居。继续这个直到你到达起始顶点。所有这些边缘都绑定了您的第一个区域。我会给它一个唯一的ID并将其分配给一个&#34;左侧区域&#34;这些边缘的属性。

查看队列中的第一个边缘并检查它是否有一个&#34;左侧区域&#34;。如果确实检查了它是否有正确的区域&#34;如果没有以顺时针方式进行并找到正确的区域。如果它分配了两个区域,则将其取出并抓住下一个区域。

应该是O(e + v)这么快,对吧?

这是一点意识流,但我想把它写下来。我将为我的实际应用编写算法,并且当我发现问题时我会进行调整。

我当然愿意接受反馈和建议:)