【问题标题】:Detecting closed loop in a 2D array pattern检测二维阵列模式中的闭环
【发布时间】:2015-09-03 09:24:48
【问题描述】:

假设你得到以下数组:

foo = [
    [0,0,0,0,0,0,0,0,0,0],
    [0,0,0,0,0,0,0,0,0,0],
    [0,0,0,1,1,1,1,1,0,0],
    [0,0,0,1,0,0,0,1,0,0],
    [0,0,0,1,0,0,0,1,0,0],
    [0,0,0,1,1,1,0,1,0,0],
    [0,0,0,0,0,1,0,1,0,0],
    [0,0,0,0,0,1,1,1,0,0],
    [0,0,0,0,0,0,0,0,0,0],
    [0,0,0,0,0,0,0,0,0,0],
]

如何判断 1 的模式是否为闭环?我已经为此苦苦挣扎了几天。我尝试了一个递归循环来查找邻居和单词,但是当你有一个更复杂的模式时它就不起作用了,例如:

foo = [
    [0,0,0,0,0,0,0,0,0,0],
    [0,0,0,0,0,0,0,0,0,0],
    [0,0,0,1,1,1,0,0,0,0],
    [0,0,0,1,0,1,0,0,0,0],
    [0,0,0,1,0,1,0,0,0,0],
    [0,0,0,1,1,1,1,1,0,0],
    [0,0,0,0,0,1,0,0,0,0],
    [0,0,0,0,0,1,0,0,0,0],
    [0,0,0,0,0,0,0,0,0,0],
    [0,0,0,0,0,0,0,0,0,0],
]

有人有一个神奇的算法来解决这个问题吗? :(

【问题讨论】:

  • 您可能希望实现Dijkstra's Algorithm 并将您的数组作为节点进行迭代。然后测试你是否已经回到你的起始位置。
  • 对不起,你想让第二个例子算作有一个闭环吗?另外,您需要在循环中使用 0 还是在平方数中需要 4 个 1?
  • 我可以看到“Flood Fill”算法在这种情况下工作,就像在油漆程序中的桶填充一样。如果您“填充”一个 0 区域并且它没有溢出数组的边缘,则它必须被关闭。不过,您必须尝试每个单独的 0 区域。
  • 是的第二个例子,一个“魔术”函数应该返回一个数组,其坐标只有 1 是一个闭环,我的递归函数可以用第一个例子做到这一点,但是当第二个例子它找到 2 个邻居函数假设一个方向并继续循环,但就像在第二个示例中一样,它可能会得到错误的方向并且没有关闭循环,它很复杂而且我的英语很糟糕我尝试了 Dijkstra 算法,但它适用于多边形,我不知道它是否适合这个问题,并且洪水填充会消耗太多的 cpu 谢谢你们想听更多的想法
  • 您可以计算循环的末端数和分叉数。如果循环是闭合的,就会有与末端一样多的分叉(可能更多)

标签: javascript arrays html5-canvas phaser-framework


【解决方案1】:

正如 Dagrooms 所说,尝试找到只有一个相邻 1 的 1(s)。代码如下所示:

function isValid1(x,y){
  return (foo[x-1][y] + foo[x+1][y] + foo[x][y-1] + foo[x][y + 1])>1;
}

function validLoop(){
  for(var i = 0; i < rows; i++){
    for(var j = 0; j < columns; j++){
      if(foo[i][j] === 1 && !isValid1(i,j)) {
        return false;
      }
    }
  }
  return true;
}

其中行和列是二维数组大小。

更新

如果至少有一个闭环,这将返回 true:

function numTouching1(x,y){
  return foo[x - 1][y] + foo[x + 1][y] + foo[x][y - 1] + foo[x][y + 1];
}

function validLoop(){
  var n = 0, x = 0; // x is current point's number of touching 1 and n is total
  for(var i = 0; i < rows; i++){
    for(var j = 0; j < columns; j++){
      if(foo[i][j] === 1) {
        x = numTouching1(i, j) - 2;
        if(x === -1 || x === 1 || x === 2){
          n += x;
        } 
      }
    }
  }
  return n > -1;
}

JSFiddle:https://jsfiddle.net/AdminXVII/b0f7th5d/

更新 2 提取循环:

function numTouching1(x,y){
  return foo[x - 1][y] + foo[x + 1][y] + foo[x][y - 1] + foo[x][y + 1];
}

function extractLoop(){
  for(var i = 0; i < rows; i++){
    for(var j = 0; j < columns; j++){
      if(foo[i][j] === 1 && numTouching1(i, j) === 1){
          foo[i][j] = 0;
          extractLoop();break;
      }
    }
  }
}

JSFiddle:https://jsfiddle.net/AdminXVII/b0f7th5d/7/

更新 3

如果有不止一个循环,这是威胁,但对于一个循环它会更慢。

function numTouching1(x, y) {
    return foo[x - 1][y] + foo[x + 1][y] + foo[x][y - 1] + foo[x][y + 1];
}

function extractLoop() {
    for (var i = 0; i < rows; i++) {
        for (var j = 0; j < columns; j++) {
            if (foo[i][j] === 1 && numTouching1(i, j) === 1) {
                foo[i][j] = 0;
                extractLoop(); break;
            }
        }
    }
}

function validLoop(){
  extractLoop();
  for(var i = 0; i < rows; i++){
    for(var j = 0; j < columns; j++){
      if(foo[i][j] === 1 && numTouching1(i,j) == 2) {
        return true;
      }
    }
  }
  return true;
}

JSFiddle:https://jsfiddle.net/AdminXVII/w7zcgpyL/

更新 4

更安全的numTouching1() 方法:

function numTouching1(x, y) {
    return ((x > 0) ? foo[x - 1][y] : 0) + ((x < rows-1) ? foo[x + 1][y] : 0) + ((y > 0) ? foo[x][y - 1] : 0) + ((y < columns-1) ? foo[x][y + 1] : 0);
}

修改了之前的JSFiddle

【讨论】:

  • 会返回100次真假?
  • @Thiago Frias 不,因为return 每次函数调用只调用一次。
  • 闭环返回true,非闭环返回false
  • @K3N 谢谢,我忘了初始化 n 所以它总是返回 false。有关 JSFiddle 测试,请参阅我的帖子
  • @K3N 不,代码很好。将 -2numTouching1() 移动到 validLoop()。它返回错误,因为它是错误的:我已将 1 更改为 0,因此它没有关闭。但是,将其更改为另一个示例
猜你喜欢
  • 2013-05-26
  • 1970-01-01
  • 2015-08-22
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-07-14
  • 2017-03-30
  • 1970-01-01
相关资源
最近更新 更多