在2d网格中查找路径并返回所有匹配的节点

时间:2013-03-09 04:46:32

标签: algorithm graph multidimensional-array path-finding graph-traversal

假设我有一个行*列网格,并且网格上的每个节点都有一个整数(状态)值。

state[NUMBER_OF_ROWS][NUMBER_OF_COLUMNS]

如果值

state[row][0] == state[row][NUMBER_OF_COLUMNS -1]

我想检查一下“路径”是否只包含这两点中的相同状态..

按路径,我的意思是左,右,底或顶的状态与原始状态相同。

我不确定它是否重要,但是让我们说状态是二进制(#或 - )所以如果我正在检查状态路径==“ - ”,我们可以继续路径如果状态为N,E,S,W也是==“ - ”

结束行必须等于起始行。

成功的例子:

|# # # # #|    
|# # # # #|    
|# # # # #|
|- # # # #|
|- - - - -|

|# # # # #|
|# # # - #|
|# - - - #|
|- - # - -|
|# # # - -|

|# # # # #|
|# # # - #|
|# # # - #|
|- - - - #|
|- # # - -|

失败的例子:

|# # # # #|
|# # # # #|
|# # # # #|
|- - - - #|
|# # - - -|

|# # # # #|
|# # # - #|
|# # # - #|
|# - - - #|
|- # # - #|

|# # # # #|
|# # - # #|
|# # # # #|
|# - # - #|
|- # - # -|

会失败。

我该怎么做?我在Objective C中编码,但是伪代码可以帮助我理解这些步骤就足够了。

除了检查BOOL是否存在路径之外,我还想返回路径中所有网格坐标的数组。

这是否易于实施,还是我在脑海中?

2 个答案:

答案 0 :(得分:0)

听起来你正在研究一个非常常见的一般编程问题的特定情况。您的网格是特定类型的图形;每个小区是可以连接到相邻节点的节点。首先看一下最简单的graph traversal策略;广度优先或深度优先搜索。这两种算法是您应该熟悉的简单工具,以及解决此特定问题所需的所有问题。 在您的情况下,您可以将搜索限制为仅能够探索包含与当前节点相同值的节点,并查看您是否能够到达目的地。

现在,这些算法中的任何一个都会告诉您路径是否存在。这是一个好的开始,但如果你想找到最短的路径怎么办?为此我们有Dijkstra's Algorithm

这很不错但我们仍然需要遍历整个图表以找到最短的路径。如果图表很小但是随着它的增长将成为一项昂贵的操作,这不是问题。有没有什么方法可以找到最短路径而无需到处搜索?有:看看A*(“明星”)算法。

答案 1 :(得分:0)

所以这是我的解决方案 - 基于@Floris链接的迷宫解决算法。

可能有一两个错误,它肯定没有优化,但现在可以使用。

非常容易理解,感谢大家的帮助:

-(BoardState)solutionPathExistsForColor {
    //create a board copy where the last column equals the first

    for (int i = 0; i < BOARD_ROWS+1; i++) {
        for (int j = 0; j < BOARD_COLUMNS+1; j++) {
            if (j == BOARD_COLUMNS) {
                loopedBoard[i][j] = landed[i][0];
            } else {
                loopedBoard[i][j] = landed[i][j];
            }
        }
    }

    for (BoardState state = 1; state < kBoardStateCount; state++) {
        //first check if it is possible there is a path


        //for each row
        for (int row = 0; row < BOARD_ROWS; row++) {

            //set solution path to zero
            for (int i = 0; i < BOARD_ROWS; i++) {
                for (int j = 0; j < BOARD_COLUMNS; j++) {
                    solutionPath[i][j] = 0;
                }
            }
            BOOL aTest = [self findPathToGoalRow:row //iterate
                                   andGoalColumn:BOARD_COLUMNS  //always the same
                                         fromRow:row  //iterate
                                       andColumn:0  // always the same
                                         ofState:state]; //iterate
            if (aTest) {
                CCLOG(@"Success! State %i", (int)state);
                //now that you know a path exists, modify the path to contain all correct adjacent cells
                [self fixSolutionPathOfColor:state];
                return state;
            } else {
                CCLOG(@"Failure!");
            }
        }
    }
    return kBoardStateVOID;
}

-(BOOL)findPathToGoalRow:(int)goalRow
           andGoalColumn:(int)goalColumn
                 fromRow:(int)fromRow
               andColumn:(int)fromColumn
                 ofState:(BoardState)state {


    //check to see if we've already seen this row and column
    if (solutionPath[fromRow][fromColumn] == 1) {
        return NO;
    }

//  if (x,y outside maze) return false
    if (fromRow > BOARD_ROWS -1 || fromColumn > BOARD_COLUMNS || fromRow < 0 || fromColumn < 0) {
        return NO;
    }
//  if (x,y is goal) return true
    if (fromRow == goalRow && fromColumn == goalColumn) {
        return YES;
    }
//  if (x,y not open) return false
    //if ([self boardStateAtRow:fromRow andColumn:fromColumn] != state) {
    if (loopedBoard[fromRow][fromColumn]!=state) {
        return NO;
    }


//  mark x,y as part of solution path
    solutionPath[fromRow][fromColumn] = 1;

//  if (FIND-PATH(North of x,y) == true) return true
    if ([self findPathToGoalRow:goalRow
                  andGoalColumn:goalColumn
                        fromRow:fromRow+1
                      andColumn:fromColumn
                        ofState:state]) {
        return YES;
    }
//  if (FIND-PATH(East of x,y) == true) return true
    if ([self findPathToGoalRow:goalRow
                  andGoalColumn:goalColumn
                        fromRow:fromRow
                      andColumn:fromColumn+1
                        ofState:state]) {
        return YES;
    }
//  if (FIND-PATH(South of x,y) == true) return true
    if ([self findPathToGoalRow:goalRow
                  andGoalColumn:goalColumn
                        fromRow:fromRow-1
                      andColumn:fromColumn
                        ofState:state]) {
        return YES;
    }
//  if (FIND-PATH(West of x,y) == true) return true
    if ([self findPathToGoalRow:goalRow
                  andGoalColumn:goalColumn
                        fromRow:fromRow
                      andColumn:fromColumn-1
                        ofState:state]) {
        return YES;
    }
//  unmark x,y as part of solution path
    solutionPath[fromRow][fromColumn] = 0;
    return NO;
}

-(void)fixSolutionPathOfColor:(BoardState)color {

    for (int column = 0; column < BOARD_COLUMNS; column++) {
        BOOL bottomColumnOfSolutionPathFound = NO;
        int checkingRow = 0;
        while (!bottomColumnOfSolutionPathFound) {
            if ([self solutionCellAtRow:checkingRow andColumn:column] == 1) {
                bottomColumnOfSolutionPathFound = YES;
            } else {
                checkingRow++;
            }
        }

        //you'll start with this bottom row and look below
        if (solutionPath[checkingRow][column] == 1) {
            int nextRowToCheck = checkingRow-1;
            BOOL keepChecking = YES;
            while (nextRowToCheck >= 0 && keepChecking) {
                if ([self boardStateAtRow:(nextRowToCheck) andColumn:column] == color) {
                    if ([self solutionCellAtRow:(nextRowToCheck) andColumn:column] != YES) {
                        solutionPath[nextRowToCheck][column] = 1;
                    }
                    nextRowToCheck--;
                } else {
                    keepChecking = NO;
                }
            }
            //now repeat for above
            nextRowToCheck = checkingRow+1;
            keepChecking = YES;
            while (nextRowToCheck < BOARD_ROWS && keepChecking) {
                if ([self boardStateAtRow:(nextRowToCheck) andColumn:column] == color) {
                    if ([self solutionCellAtRow:(nextRowToCheck) andColumn:column] != YES) {
                        solutionPath[nextRowToCheck][column] = 1;
                    }
                    nextRowToCheck++;
                } else {
                    keepChecking = NO;
                }
            }
        }
    }
}

谢谢!