【问题标题】:converting incidence matrix to adjacency matrix将关联矩阵转换为邻接矩阵
【发布时间】:2021-12-31 17:56:47
【问题描述】:

如何正确实现关联矩阵到邻接矩阵的转换算法?

图表将是无向的

不幸的是,我尝试做的算法不起作用

const readline = require('readline')
        
const rl = readline.createInterface({input: process.stdin, output: process.stdout})
let arr = []
rl.question('Matrix N and M: ', async (userInput) => {
    const input = await userInput.split(' ')
    const arrayLength = input[0]
    const maxWidth = input[1]
    matrix(arrayLength, maxWidth)
})

const matrix = (arrayLength, maxWidth) => { 
    if(arrayLength === 0){
        convert(maxWidth)
    }
    if(arrayLength > 0){
        rl.question(`Row: ${arrayLength}, enter numbers separated by spaces: `, async (userInput) => {
            const subArray = await userInput.split(' ')
            subArray.length = maxWidth
            await arr.push(subArray)
            matrix(arrayLength - 1, maxWidth)
        })
    }
}
const convert = (maxWidth) => {
    let matrix = []
    let subArray = []
    for (let i = 0; i < arr.length; i++) {
        for (let j = 0; j < maxWidth; j++) {
     }
  }
}

【问题讨论】:

  • 您能解释一下您的意见吗? 3是顶点数吗? 2 是边数?
  • 是的,就像你得到它的方式
  • 好的,你的输入让它看起来像是一个有向图,这也是真的吗?
  • 不,这不是有向图
  • 哦,我明白你要做什么了。您希望input 生成一个包含指定连接的n * m 数组。这个问题有点不清楚。我建议您编辑以包括上面提出的问题。

标签: javascript node.js algorithm graph


【解决方案1】:

所以有几件事(缺乏问题根源)。 但是,这是您可以使用的一种方法。 在这里,地图用于存储边和顶点之间的关系。使用它,我们可以通过分组来构建顶点之间的关系。

为了方便使用,我们首先使用promise-based问题函数。这可以使用以下方法完成

const readline = require("readline");

const rl = readline.createInterface({
  input: process.stdin,
  output: process.stdout,
});

// Convert question function from cb to promise.
const question = (query) =>
  new Promise((resolve, _) => {
    rl.question(query, (input) => resolve(input));
  });

接下来,我们创建一个 main 函数来封装我们的逻辑。

async function main() {}

现在,让我们创建一个为我们提取维数的函数

async function getDimensions() { 
  // # of Vertices x # of Edges
  return (await question("Matrix N and M: ")).split(" ").map(x => +x)
}

完成后,我们可以创建两个辅助函数。 第一个,它接受预期顶点的数量。 第二个,它采用最终的incidentMap和预期顶点的数量(所以我们不必计算它)。

  async function createIncidenceMap(N) { }
  async function convertToAdjacencyMatrix(incidenceMap, N) { }

要实现createIncidentMap,我们可以使用下面的

// Create an Incidence Map for Quick Look Up
async function createIncidenceMap(N) {
  const incidentMatrix = [];

  // Read in the relationships between edges (columns) and vertices (rows).
  for (let i = 0; i < N; i++) {
    const result = (
      await question(`Row: ${i}, enter numbers separated by spaces: `)
    )
      .split(" ")
      .map((x) => +x);
    incidentMatrix.push(result);
  }

  // Group vertices by edges.
  return incidentMatrix.reduce((incidentMap, incidentPair, M) => {
    const incidentSubset = incidentPair.reduce(
      (subsetMap, connected, N) => (
        {
          ...subsetMap,
          [N]: [
            ...(subsetMap[N]?.length ? subsetMap[N] : []),
            ...(connected ? [M] : []),
          ],
        }
      ),
      {}
    );

    // Join previous vertices connected to the same edge.
    return Object.keys(incidentSubset).reduce((map, edge, index) => ({
      ...map,
      [edge]: new Set([
        ...(incidentMap[edge] ?? []),
        ...incidentSubset[edge]
      ]).values(),
    }), {});
  }, {});
};

这将减少 convertToAdjacencyMatrix 的工作量

function convertToAdjacencyMatrix(incidenceMap, M) {
  const connectedPairs = Object.values(incidenceMap).map(x => [...x])
  // (M x M)
  const adjacencyMatrix = new Array(M)
    .fill(0).map(_ => new Array(M).fill(0));

  connectedPairs.forEach(pair => {
    const [n1, n2] = pair
    // A vertice always has a relationship with itself.
    adjacencyMatrix[n1][n1] = 1
    adjacencyMatrix[n2][n2] = 1

    // Mark the relationship between the vertices sharing the same edge.
    adjacencyMatrix[n1][n2] = 1
    adjacencyMatrix[n2][n1] = 1
  })

  return adjacencyMatrix
};

最后我们结合main中的逻辑得到

async function main() {
  try {
    const[N,M] = await getDimensions()

    // Create incidentMatrix for faster conversion.
    const incidenceMap = await createIncidenceMap(N);
    // Convert.
    const adjacencyMatrix = convertToAdjacencyMatrix(incidenceMap, N)
    console.log(adjacencyMatrix)
    rl.close();
  } catch (err) {
    console.log(`Error found when reading ${err}`);
  }
}

使用您提供的输入调用 main 将产生

// [ [ 1, 1, 0 ], [ 1, 1, 1 ], [ 0, 1, 1 ] ]
main()

正如预期的那样。

一个完整的例子可以在这个demo中找到

【讨论】:

    【解决方案2】:

    这不会尝试进行任何输入解析,但它确实接受关联矩阵(作为数组的数组,这在 JS 中很典型)并以相同的方式返回邻接矩阵。它不进行错误检查以确保您提供的实际上是一个关联矩阵(其中每一列在其他任何地方都有两个 1s 和 0s。)这并不难添加,

    它使用range 辅助函数,该函数返回一个介于低值(包括)和高值(不包括)之间的整数数组。例如,range (3, 12) 返回[3, 4, 5, 6, 7, 8, 9, 10, 11]

    主函数对输入中的行数进行双循环,迭代值表示行和列。对于每一个,我们检查输入中是否有任何列作为两个索引的值1(排除两个索引相同的列之后。)

    看起来像这样:

    const range = (lo, hi) => 
      Array.from ({length: hi - lo}, (_, i) => i + lo)
    
    const inci2adj = (m) => 
      range (0, m .length) .map (
        j => range (0, m .length) .map (i => m [0] .some (
          (_, e) => i !== j &&  m [i] [e] == 1 && m [j] [e] == 1) ? 1 : 0
        )
      )
    
    const incidents = [
      [1, 0], 
      [1, 1], 
      [0, 1]
    ]
    
    console .log (inci2adj (incidents))
    .as-console-wrapper {max-height: 100% !important; top: 0}

    请注意,虽然图有一个确定的邻接矩阵,但关联矩阵有多种表示形式,因为列的重新排列仍将表示同一个图。

    这意味着如果我们从一个邻接矩阵开始,对它运行 adj2inci from a related answer1,然后在结果上运行 inci2adj,我们将得到相同的矩阵我们从。但是如果我们从关联矩阵开始,对它运行inci2adj,然后在结果上运行adj2inci,我们不一定会得到原始矩阵。


    1代码如下:

    const adj2inci = (m) => 
      transpose (range (0, m .length) 
        .flatMap (j => range (0, j + 1) .flatMap (
          i => m[j][i] == 1 ? [Object .assign (Array (m .length) .fill (0), {[i]: 1}, {[j]: 1})] : [])
        )
      )
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2021-06-05
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多