将2D矩阵转换为图形

时间:2014-08-20 12:48:29

标签: java algorithm graph

在将包含无效点和有效点的给定2D矩阵转换为仅包含有效节点的图形时,我遇到了问题。问题是这样的。 我有像

这样的2D矩阵
# # # # #
# . C C #
# S # # #
# . . E #
# # # # # 

我想找到从S到E的最短距离,记住我必须覆盖所有'C'和'#'作为墙和''。充当自由之路。 现在我想将此矩阵转换为仅包含有效节点的图形。 请帮助我。

n = number of nodes
for i=1 to n: for j=1 to n: d[i][j]=INF
 for k=1 to n:
   for i=1 to n:
    for j=1 to n:
        d[i][j] = min(d[i][j], d[i][k] + d[k][j])

shortest = INF
for each permutation a[1],a[2],...a[k] of the 'mustpass' nodes:
  shortest = min(shortest, d['start'][a[1]]+d[a[1]][a[2]]+...+d[a[k]]['end'])
print shortest

4 个答案:

答案 0 :(得分:3)

字符的2d矩阵是此问题的完美精细图形表示。

每个矩阵元素(i,j)是节点。假设您只能跨越东,西,北,南,则从该节点到其邻居(i +或-1,j +或-1)存在0到4个无向边,这通过简单地测试每个位置中的字符来确定。

您还可以测试i,j值超出范围(负值或太大),但是如果总是存在"墙壁"如图所示,这不是必需的。该墙用作sentinel

构建一个通用结构来表示嵌入网格中的图形是浪费时间和内存。

答案 1 :(得分:2)

为了制作图表,您必须为每个非墙空间生成一个节点。浏览2D矩阵(假设它只是一个char数组)并创建节点并添加边缘:

nodes = new Node[matrix.length][matrix[0].length]; //instance variable

for ( int row = 0; row < matrix.length; row++ )
{
  for ( int col = 0; col < matrix[row].length; col++ )
  {
    char type = matrix[row][col];
    if ( type != '#' )
    {
      Node n = new Node();
      nodes[row][col] = n; //constructor to determine type of node
      if ( type == 'S' )
        startNode = n;
      else if ( type == 'E' )
        endNode = n;

      findNeighbors(row, col); //assuming nodes and matrix variables are instance variables
    }
    else
      nodes[row][col] = null;
  }
}

使用2D节点阵列,您可以通过findNeighbors:

进行添加
public void findNeighbors(int row, int col)
{
  for ( int r = -1; r <= 1; r++ )
  {
    for ( int c = -1; c <= 1; c++ )
    {
      try { 
        if ( matrix[row+r][col+c] != '#' ) 
          nodes[row][col].addEdge(nodes[row+r][col+c]);
      } catch (ArrayIndexOutOfBoundsException e) {}
    }
  }
}

现在,在所有代码之后,您有一个表示图形的Node对象的2D数组。您可以将Start节点存储在实例变量中,以便方便地引用它并轻松访问其邻居。

使用我编写的代码,Node类需要一个方法addEdge(Node),它将参数节点添加到节点列表中。

答案 2 :(得分:1)

这看起来像是一个家庭作业,但为了对话(时间/空间复杂性),我会做一些与众不同的事情。首先,我将创建一个Graph,它只包含可以是路径(例如不是墙)的节点之间的有效边。这最小化了所需的空间。我不会使用矩阵,因为它在实际图形(稀疏)中使用了太多空间,时间复杂度为ROW * COL(方形矩阵的V ^ 2)。

class Graph {
    Map<Integer, Set<Integer>> edgeTo;

    Graph() {
        this.edgeTo = new HashMap<Integer, Set<Integer>>();
    }

    public int size() {
        return edgeTo.size();
    }

    public void addEdge(int v1, int v2) {
        add(v1, v2);
        add(v2, v1);
    }

    private void add(int from, int to) {
        if (!edgeTo.containsKey(from)) {
            Set<Integer> s = new HashSet<Integer>();
            s.add(to);
            edgeTo.put(from, s);
        } else {
            edgeTo.get(from).add(to);
        }
    }

    public Set<Integer> adj(int v) {
        return edgeTo.get(v);
    }
}

有了这个原位,图表的创建遵循上一篇文章的想法,

    private Graph createGrap(char[][] matrix) {
    Graph g = new Graph();
    for (int r = 0; r < matrix.length; r++) {
        for (int c = 0; c < matrix[0].length; c++) {

            // skip this cells
            if (!isFreeCell(matrix[r][c])) {
                continue;
            }

            int id = createUniqueId(r, c);
            if (matrix[r][c] == 'S') {
                startVertex = id;
            } else if (matrix[r][c] == 'E') {
                endVertex = id;
            }
            createNeighbor(r, c, matrix, g);
        }
    }
    return g;
}

private void createNeighbor(final int r, final int c, final char[][] matrix2, final Graph g) {
    for (int row = -1; row <= 1; row++) {
        for (int col = -1; col <= 1; col++) {
            // avoid the center cell
            if (row ==0 && col == 0){
                continue;
            }
            // outside matrix
            if ((0 > c + col) || (c + col >= matrix2[0].length) || (0 > r + row) || (r + row >= matrix2.length)) {
                continue;
            }
            char value = matrix2[r+row][c+col];
            if (!isFreeCell(value)){
                continue;
            }
            int from = createUniqueId(r, c);
            int to = createUniqueId(row+r, col+c);
            g.add(from, to);
        }
    }

}

private boolean isFreeCell(char value) {
    return (value != '#' && value !='C');
}

private int createUniqueId(int r, int c) {
    return r * MAX_COL + c;
}

现在唯一剩下的就是找到最短路径...使用这个无向图的BFS,没有负的权重边...

private void findSP(Graph g) {
    if (g == null || g.size() == 0) {
        throw new IllegalArgumentException("empty or null graph");
    }

    if (g.size() == 1) {
        throw new IllegalArgumentException(
                "graph's size must be greater than 1");
    }

    if (startVertex == -1) {
        throw new IllegalArgumentException("Start vertex not found");
    }

    if (endVertex == -1) {
        throw new IllegalArgumentException("End vertex not found");
    }

    Map<Integer, Integer> sonToParent = bfs(g, startVertex, endVertex);

    Stack<Integer> path = new Stack<Integer>();
    for (int son = endVertex; son!= startVertex; son = sonToParent.get(son)){
        path.push(son);
    }

    path.push(startVertex);
    while (!path.isEmpty()){
        System.out.print(path.pop() + ", ");
    }
}

private Map<Integer, Integer> bfs(Graph g, int startVertex2, int endVertex2) {
    Queue<Integer> q = new LinkedList<Integer>();
    Set<Integer> marked = new HashSet<Integer>();
    Map<Integer, Integer> sonToParent = new HashMap<Integer, Integer>();
    q.add(startVertex2);
    while (!q.isEmpty()) {
        int v = q.poll();
        for (Integer s : g.adj(v)) {
            if (!marked.contains(s)) {
                marked.add(s);
                sonToParent.put(s, v);

                if (s == endVertex2) {
                    return sonToParent;
                }

                q.add(s);
            }
        }

    }
    return null;
}

答案 3 :(得分:0)

我要么创建一个节点结构,要么创建一个节点类。例如:

struct Node {
    node type;  //Indicate in some way if the node is a 'S', '.' or 'E'
    std::vector<Node> adjacentNodes;
}

就填充此数据结构而言,我将从'S'块开始。并进行递归调用,如:

Set alreadyVisited;

FillGraph(i,j,Node){
//    for all adjacent nodes, add them to Node's adjacentNodes.
//    add Node to alreadyVisited Set
//    for each of the adjacentNodes (i.e. any neighbor that isn't a wall.
//       if(adjacentNode is not in alreadyVisited)
//          FillGraph(adjaent-i, adjacent-j, adjacentNode);
}