简短回答:是的,你总是可以做得比O(N^3 log K) 更好。
长答案:最快方法的复杂性确实取决于 K 的大小,并且在较小程度上取决于图的当前表示形式和图中的边数。这个问题的具体术语是“counting closed walks”。
小K
使用动态编程。对于给定的初始顶点 x,我们有一个二维 DP 状态。
令 DP[ y ][ i ] 为从我们初始开始的长度为 i 的游走数
到 y 的顶点。如果 y 与我们的初始值相邻,则 DP[ y ][ 1 ] 为 1
顶点,否则为 0。 i 的递推关系 >
1 是:DP[ y ][ i ] 是 (DP[ w ][ i - 1 ]) 的 y 的所有邻居 w 的总和
那么你的答案就是 DP[ K ][ 1 ]。
执行此操作的简短 Python 代码,假设图是邻接表表示:
dp = [[0 for _ in range(N + 1)] for _ in range(K + 1)]
for neighbor in graph[1]:
dp[1][neighbor] = 1
for walk_length in range(2, K + 1):
for vertex in range(1, N + 1):
for neighbor in graph[vertex]:
dp[walk_length][neighbor] += dp[walk_length - 1][vertex]
print(dp[K][1])
时间复杂度为O(K * (N + E)),其中 E 是边数。额外的空间复杂度为O(NK),稍加努力即可降为O(N)。如果你的图很密集,它最多有|E| = O(N^2),所以这是O(K * N * N);如果你的图是稀疏的,就像一棵树,这是O(K * N)。邻接矩阵和邻接表之间的转换是O(N^2)的一个加法因子。
大K
据我所知,对于大 K 的最佳答案(复杂性)是使用类似于您建议的 adjacency matrix exponentiation 的策略。这种方法是有效的,但我们可以更聪明一点。
回想一下,未加权、无向图的邻接矩阵是实对称矩阵,因此它是diagonalizable. 设邻接矩阵为 A,谱分解为 A = P * D * (P^- 1),其中 D 是对角矩阵。然后我们找到 A^K = P * (D^K) * (P^-1) 的左上元素,这需要对单个特征值进行 N 次幂运算,然后是 2N 次乘法和加法。
由于特征值的大小受最大度数或O(N) 的限制,因此主导项由计算具有 O(log N) 位数的数字 x 的 x^K 的成本决定。确定这里的时间复杂度很复杂:我们必须开始讨论计算模型,以及整数乘法的成本。如果我们谈论的是计算的词 RAM 模型,或者机器词足够大以处理输出的模型,那么您的 O(N^3 log K) 绑定就可以工作。如果您只想要以某个固定数字为模的答案,它也可以更普遍地工作。否则,如果 K 任意大,我们的 N 个特征值幂每个可以有 O(K) 位,所以这最后一步可能需要 O( K * N log log N) 时间,这仍然比原始的全矩阵求幂更有效(至少是 @987654336 @ 在这种情况下)。
矩阵分解的复杂度与矩阵乘法的复杂度密切相关,这是一个开放性问题。介于 N^2 和 N^(2.373) 之间,但理论上最优复杂度的问题是best addressed in math stackexchange questions like this one,通常与实际问题无关。