【问题标题】:Optimizing an adjacency matrix creation from a 2D array of nodes从二维节点数组优化邻接矩阵创建
【发布时间】:2015-02-25 16:08:39
【问题描述】:

我正在尝试从二维节点数组创建邻接矩阵。邻接矩阵将被传递给一个程序,该程序将通过以下方式对节点进行聚类

  1. 光谱聚类算法
  2. Kmeans 聚类算法

**节点类**

    public class Node{
    public int _id;
    public bool _isWalkable;
    public int _positionX;
    public int _positionY;
    public Vector3 _worldPosition;
    }

网格类

    public class Grid : MonoBehaviour
    {

        void CreateGrid()
        {
        grid = new Node[_gridSizeX, _gridSizeY];
        Vector3 worldBottomLeft =  transform.position - 
        Vector3.right * worldSize.x / 2 - Vector3.forward * worldSize.y / 2;

        //set the grid
        int id = 0;

        for (int x = 0; x < _gridSizeX; x++)
        {
            for (int y = 0; y < _gridSizeY; y++)
            {
                Vector3 worldPosition = worldBottomLeft + Vector3.right * 
                    (x * _nodeDiameter + _nodeRadius) + 
                    Vector3.forward * (y * _nodeDiameter + _nodeRadius);
                //check to see if current position is walkable
                bool isWalkable = 
                    !Physics.CheckSphere(worldPosition, _nodeRadius, UnwalkableMask);

                grid[x, y] = new Node(isWalkable, worldPosition, x, y);
                grid[x, y].Id = id ++;

            }
        }
        totalNodes = id;
    }
}

节点存储在称为网格的二维数组中,表示角色移动的可行走路径。我已经成功地实现了一个带有欧几里德距离启发式的 A* 算法。我想做的是使用上述聚类算法对这些节点进行聚类,但首先我需要为它们创建一个邻接算法。这是我能想到的最好的伪代码

    int[][] _adjacencyMatrix = new int[gridSizeX*gridSizeY][gridSizeX*gridSizeY];

    for(int x = 0; x < gridSize;x< XgridSize; i++)
    {
         for(int y = 0; y < gridSize;y< YgridSize; i++)
         {
           if( !Grid[x][y]._isWalkable)
              continue;
           Node n = Grid[x][y];
           List<Node> neighbors = GetNeighbors(n);
           for(int k; k<neighbors.Count(); k++)
            {
                _adjacencyMatrix[n._id][neighbors[k]._id]=1; 
            }
         }
    }

    public List<Node> GetNeighbours(Node n)
    {
        //where is this node in the grid?
        List<Node> neighbours = new List<Node>();

        //this will search in a 3X3 block
        for (int x = -1; x <= 1; x++)
        {
            for (int y = -1; y <= 1; y++)
            {
                if (x == 0 && y == 0)
                    continue; //we're at the current node

                int checkX = n._positionX + x;
                int checkY = n._positionY + y;

                if (checkX >= 0 && checkX < _gridSizeX && checkY >= 0 
                    && checkY < _gridSizeY)
                {
                    if(grid[checkX, checkY]._isWalkable)
                        neighbours.Add(grid[checkX, checkY]);
                    else
                        continue;
                }
            }

        }
        return neighbours;

    }

我最关心的问题

我主要关心的是上述算法的总体复杂性。感觉它会很重,我在一个大小为 5625X5625 的邻接矩阵中总共有 (75^2 = 5625) 个节点!一定有比这更好的寻找邻居的方法,是吗?

【问题讨论】:

  • 你不应该在某处检查 n.isWalkable() 吗?
  • kmeans 不使用成对距离。

标签: c# unity3d cluster-analysis adjacency-matrix


【解决方案1】:

矩阵是对称的,所以你只需要保存一半,例子见(How to store a symmetric matrix?)。矩阵值是二进制的,因此将它们保存为布尔值或位向量将分别减少 4 或 32 倍的内存。

另外,由于检查两个相邻节点需要恒定时间 (abs(n1.x - n2.x) &lt;= 1 &amp;&amp; abs(n1.y - n1.y) &lt;= 1 &amp;&amp; grid[n1.x, n2.x].isWalkable() &amp;&amp; grid[n2.x, n2.y]),您可以只向聚类算法传递一个动态检查邻接的函数。

【讨论】:

    【解决方案2】:

    5k x 5k 不是很大。 100 MB 是可以保留在内存中的。如果您想避免这种成本,请不要使用基于距离矩阵的算法!

    但是,由于您的相似性似乎是

    d(x,y) = 1 如果相邻且两个节点都可行走否则 0

    你的结果会退化。如果你幸运的话,你会得到类似连接组件的东西(你本来可以更容易的)。 成对最短路径会更有用,但构建起来也更昂贵。不过,也许可以考虑先解决这个问题。我想拥有一个完整的邻接矩阵是一个很好的起点。

    k-means 根本无法处理成对距离。对于任意方法,它只需要点到平均的距离。

    我建议先查看图算法,并花更多时间了解您的目标,然后再尝试将数据压缩到可能解决不同问题的聚类算法中。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2011-02-11
      • 2019-09-09
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-12-07
      • 1970-01-01
      相关资源
      最近更新 更多