【问题标题】:Searching a grid of points, visting each point once only搜索点网格,每个点只访问一次
【发布时间】:2015-11-18 16:14:33
【问题描述】:

我有一个 (d) 维度的网格,所有维度都使用 delta = 0.25 进行分区

这个网格的一个例子就是这个图(d这里是2,每个维度归一化0-1):

每个交点代表1个点,例如中间的点表示为:

double[] A={0.5, 0.5};

我的问题是: 我想搜索这个网格,从输入点 A 及其邻居开始。然后继续这样做。有一个条件:每个点只被访问一次。

为了更清楚,请考虑以下示例: 起点是:

double[] A={0.5, 0.5};

因此,首先检查 A,然后生成其邻居并将其插入队列(队列基于函数 f 排序)。

这里的A点是黑圈。它的邻居是绿色圆圈:

{0.25, 0.25}
{0.25, 0.5}
{0.25, 0.75}
..
..
..
{0.75, 0.75}

现在,算法循环,直到队列变空。 在循环中,顶点被移除(pop()),然后被检查,然后它的邻居被添加到队列中。

例如,在第一个循环中,蓝色圆圈恰好是队列中的最高点。 它从队列中移除,然后检查,然后生成它的邻居(红色圆圈)并添加到队列中。

这里的问题是,我生成邻居点的代码不知道之前是否访问过前一个点。

而且我无法保留以前访问过的点的列表,并且每次生成新点时都要检查它(具有高维度和高分辨率,例如 d=8 和 delta= 0.03125,这将永远需要!)

这是搜索算法:

public void search(int d, double delta, double[] inpoint)
{
    Queue queue = new Queue();
    queue.push(inpoint);

    while( !queue.isEmpty() )
    {
        // remove top point from Queue
        double[] a = queue.pop();

        // Check point a and do some calculations
        // ;;;;;;;;;;;;;;;;

        // Generate neighbours of current point:
        ArrayList<double[]> neighbors = new ArrayList<double[]>();
        nextMoves(a, new double[d], delta, d, neighbors);

        // For each point in neighbors, push to Queue:
        for( int i=0 ; i < neighbors.size(), i++ )
            queue.push(neighbors.get(i));
    }
}

这是生成邻居的算法,它是一种递归算法。

public static void nextMoves(double[] inatt, double[] outatt, double delta, int d, ArrayList<double[]> neighbors) 
{
    if( d == inatt.length )
    {
        if( !outOfBound(outatt,d) )
        {
            moves.add(outatt);   
        }
    }
    else
    {
       // first case: add delta:
       outatt[d] = inatt[d]+delta; 
       nextMoves( inatt, outatt, delta, d+1, moves);

       // second case: subtract delta:
       outatt[d] = inatt[d]-delta; 
       nextMoves( inatt, outatt, delta, d+1, moves);

       // third case: no change:
       outatt[d] = inatt[d]; 
       nextMoves( inatt, outatt, delta, d+1, moves);
    }
} 

正如我之前提到的,保留以前访问过的点的列表不是一个可行的解决方案。 如果我这样做,那么当我具有高维度和高分辨率时,列表会变得非常大。 并且每次创建一个点时都必须线性搜索此列表!

也许我应该在空间索引中组织这个列表?我不知道... 非常感谢您的意见。

【问题讨论】:

  • 您能告诉我们您打算在每个点执行什么操作吗?我怀疑是否存在您计划“访问”每个点而不在那里做某事的任何现实世界问题。
  • And this list will have to be searched linearly each time a point is created ... 不,如果您可以简单地 access 使用数组中的点,则不必搜索整个列表来检查重复点问题。
  • 您的队列类是 FIFO(先进先出)吗?它是否允许检查元素是否已经存在于队列中?
  • @TarunGupta 是的,它是 FIFO。当前代码不检查队列是否已经有要添加的点。这实际上是我要添加的支票所在的位置。如果查看 nextMoves() 函数,在检查该点是否在边界内之后,这里我应该检查它是否已经在队列中,以及之前是否已访问过。
  • @TimBiegeleisen 相信我,如果你设置 d=10 和 delta = 0.03125,你最终会得到大量的分数,这将需要很长时间来检查!

标签: java search grid


【解决方案1】:

您可以考虑几个潜在的捷径:

  1. 添加所有周围点后,您可以从“以前访问过”列表中删除点。原因很简单:它们只能从周围的点添加。这意味着只有访问体积的表面需要在列表中。在更高的维度上,这将是一个可观的节省。

  2. 更复杂的是存储体积的形状而不是点。这意味着记录体积表面上的每个拐点并测试每个新点是否在该表面上。

第一个更简单,但效率不高。我建议从那个开始,看看是否足够。

【讨论】:

    【解决方案2】:

    您不必存储所有访问点。四处走动并首先收集所有邻居,并从这些点构建一个 hashkey 以将其存储在 hashmap 中。然后使用您的代码验证所有这些点并收集下一个邻居圈。在最坏的情况下,你从中间开始。然后哈希键的计算时间在算法结束时很高。为了解决这个问题,您可以先构建集群并在集群内搜索。

    您也可以从集群开始。建立一个集群布局,用上面的circle方法开始在这个集群内搜索。

    【讨论】:

      【解决方案3】:

      这听起来类似于寻路问题,您可能还需要解析一个网格并且不需要重新访问节点。 如果它适合您,请在每个访问的节点上设置一个布尔值,这样如果算法再次发生在它身上,它就知道不需要检查它。 查看Djikstras Algorithm 以获得灵感。

      【讨论】:

      • 问题在于多维性和全连接图。 Djikstra 不是一个好的解决方案,因为它适用于 2D 而不是 8D。你将不得不采取蚂蚁算法或粒子群优化。但这些是带有随机元素的元启发式算法,并没有在每次运行时为您提供最佳解决方案。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-08-21
      • 1970-01-01
      • 2014-03-30
      • 2015-08-09
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多