简体   繁体   English

给定一个邻接图和多次遍历,优化查找最遍历的边的方法

[英]Optimizing a method to find the most traversed edge given an adjacency graph and several traversals

I am given N vertices of a tree and its corresponding adjacency graph represented as an N by N array, adjGraph[N][N] . 给我一棵树的N个顶点及其对应的邻接图,用N数组adjGraph[N][N]表示为N。 For example, if (1,3) is an edge, then adjGraph[0][2] == 1 . 例如,如果(1,3)是边,则adjGraph[0][2] == 1 Otherwise, adjGraph[i][j] == 0 for (i,j)s that are not edges. 否则,对于不是边缘的(i,j)s, adjGraph[i][j] == 0

I'm given a series of inputs in the form of: 我得到了以下形式的一系列输入:

1 5

which denote that a path has been traversed starting from vertex 1 to vertex 5. I wish to find the edge that was travesed the most times, along with the number of times it was traversed. 表示从顶点1到顶点5已经遍历了一条路径。我希望找到被遍历次数最多的边以及遍历的次数。 To do this, I have another N by N array, numPass[N][N] , whose elements I first initialize to 0, then increment by 1 every time I identify a path that includes an edge that matches its index. 为此,我有另一个N by N数组numPass[N][N] ,我首先将其元素初始化为0,然后每当我确定包含与其索引匹配的边的路径时,将其元素递增1。 For example, if path (2,4) included edges (2,3) and (3,4), I would increment numPass[1][2] and numPass[2][3] by 1 each. 例如,如果路径(2,4)包含边(2,3)和(3,4),则我将numPass[1][2]numPass[2][3]增加1。

As I understand it, the main issue to tackle is that the inputs only give information of the starting vertex and ending vertex, and it is up to me to figure out which edges connect the two. 据我了解,要解决的主要问题是输入仅提供起始顶点和终止顶点的信息,并且由我自己确定哪个边将两者连接。 Since the given graph is a tree, any path between two vertices is unique. 由于给定的图是一棵树,因此两个顶点之间的任何路径都是唯一的。 Therefore, I assumed that given the index of the ending vertex for any input path, I would be able to recursively backtrack which edges were connected. 因此,我假定在给定任何输入路径的终点顶点的索引的情况下,我将能够递归地回溯连接了哪些边。

The following is the function code that I have tried to implement with that idea in mind: 以下是我牢记这一想法尝试实现的功能代码:

// find the (unique) path of edges from vertices x to y
// and increment edges crossed during such a path
void findPath(int x, int y, int N, int adjGraph[][N], int numPass[][N]) {
int temp;

// if the path is a single edge, case is trivial
if (adjGraph[x][y] == 1) {
    numPass[x][y] += 1;
    return;
}

// otherwise, find path by backtracking from y
backtrack: while (1) {
    temp = y-1;
    if (adjGraph[temp][y] == 1) {
        numPass[temp][y] += 1;
        break;
    }
}
if (adjGraph[x][temp] == 1) {
    numPass[x][temp] += 1;
    return;
} else {
    y = temp;
    goto backtrack;
}

However, the problem is that while my code works fine for small inputs, it runs out of memory for large inputs, since I have a required memory limit of 128MB and time limit of 1 second. 但是,问题是,尽管我的代码对于小型输入可以正常工作,但对于大型输入却会用尽内存,因为我的内存限制为128MB,时间限制为1秒。 The ranges for the inputs are up to 222222 vertices, and 222222 input paths. 输入范围最多为222222个顶点和222222个输入路径。

How could I optimize my method to satisfy such large inputs? 如何优化我的方法以满足如此大量的输入?

  1. Get rid of the adjacency matrix (it uses O(N^2) space). 摆脱邻接矩阵(它使用O(N^2)空间)。 Use adjacency lists instead. 请改用邻接表。

  2. Use a more efficient algorithm. 使用更有效的算法。 Let's make the tree rooted. 让我们将树植根。 For a path from a to b we can add 1 to a and b and subtract 1 from their lca (it is easy to see that this way a one is added to edges on this path and only to them). 对于从ab的路径,我们可以在ab加1并从其lca中减去1(很容易看到,将a加到该路径的边上并且仅添加到它们)。

  3. After processing all paths, the number of paths going through the edge is just a sum in the subtree. 处理完所有路径后,经过边缘的路径数只是子树中的总和。

If we use an efficient algorithm to compute lca, this solution works in O(N + Q * log N) , where Q is the number of paths. 如果我们使用高效的算法来计算lca,则此解决方案适用于O(N + Q * log N) ,其中Q是路径数。 It looks good enough for this constraints (we can actually do even better by using more complex and more efficient algorithms for finding the lca, but I don't think it's necessary here). 对于这种约束,它看起来已经足够好了(实际上,通过使用更复杂,更有效的算法来查找lca,我们甚至可以做得更好,但我认为这里没有必要)。

Note: lca means lowest common ancestor. 注意:lca表示最低的共同祖先。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM