算法:矩阵遍历变化

时间:2012-12-07 18:58:27

标签: algorithm data-structures

有一个N×N方形网格状电线网格,如下图所示。网格的节点位于点(X,Y),其中X和Y是从0到N-1的整数。电流在(0,0)和(N-1,N-1)处的节点之间流过电网。 enter image description here

最初,所有导线都传导电流,但导线以每秒一个的速率烧毁。烧坏由三个零索引的整数数组A,B和C描述,每个整数大小为M.对于每个时刻T(0≤T

    (A[T], B[T] + 1), if C[T] = 0 or
    (A[T] + 1, B[T]), if C[T] = 1
烧伤了。您可以假设阵列描述了现有的电线,并且没有电线烧坏多次。您的任务是确定当前电流何时停止在(0,0)和(N-1,N-1)的节点之间流动。

写一个函数:

int wire_burnouts(int N, int A[], int M, int B[], int M2, int C[], int M3); 

给定整数N和数组A,B和C,返回当前在(0,0)和(N-1,N-1)处的节点之间停止流动的秒数。如果在所有M线烧坏后电流仍然保持流动,则该功能应返回-1。

例如,给定N = 4,M = 9且以下数组:

A [0] = 0 B [0] = 0 C [0] = 0
  1 = 1 B 1 = 1 C 1 = 1   2 = 1 B 2 = 1 C 2 = 0
  A [3] = 2 B [3] = 1 C [3] = 0
  A [4] = 3 B [4] = 2 C [4] = 0
  A [5] = 2 B [5] = 2 C [5] = 1
  A [6] = 1 B [6] = 3 C [6] = 1
  A [7] = 0 B [7] = 1 C [7] = 0
  A [8] = 0 B [8] = 0 C [8] = 1

你的函数应该返回8,因为在第八根线烧坏后,(0,0)和(N-1,N-1)的节点之间没有连接。这种情况如下图所示:

enter image description here

给定N = 4,M = 1且以下数组:

A [0] = 0 B [0] = 0 C [0] = 0

你的函数应该返回-1,因为烧掉一根导线不能破坏(0,0)和(N-1,N-1)节点之间的连接。

假设:

    N is an integer within the range [1..400];
    M is an integer within the range [0..2*N*(N−1)];
    each element of array A is an integer within the range [0..N−1];
    each element of array B is an integer within the range [0..N−1];
    each element of array C is an integer within the range [0..1].

复杂度:

    expected worst-case time complexity is O(N2*log(N));
    expected worst-case space complexity is O(N2), beyond input storage (not counting the storage required for input arguments).

1 个答案:

答案 0 :(得分:5)

构建完整的电线网格。然后摧毁第一条M / 2线。使用深度优先搜索检查连接。如果仍然连接,则消灭M / 4个电线。如果没有,恢复M / 4最近被破坏的电线。继续这个二进制搜索,直到找到正确的T.

时间复杂度由深度优先搜索的数量确定:O(log M)< = O(log N)和每个深度优先搜索的复杂度:O(N 2 )。


使用Disjoint-set data structure可以改善以前的结果。

构建完整的电线网格。然后按照数组A,B和C的指示销毁M线。将网格的其余连接组件添加到不相交的数据结构中。

然后从这些数组的最后一个元素开始依次恢复连线并转到它们的第一个元素。在执行此操作时,找到以不相交集结构保留的集合的并集。当包含节点(0,0)和(N-1,N-1)的集合连接在一起时停止。

如果不相交集数据结构使用 union by rank path compression 方法,则整个算法的时间复杂度为O(N 2 α(N)),其中α是逆阿克曼函数。这实际上与O(N 2 )一样好。


如果我们使用与原始网格网格相对应的图形,则可以改进先前的结果:双图形的节点对应于原始图形的面,双图形的每个边缘与原始图形的对应边缘相交。将需要两个额外的节点:节点L连接到双图的每个顶部和左侧节点,节点R连接到每个底部和右侧节点。

dual graph

如果此双图包含从L到R的路径,则节点(0,0)和(N-1,N-1)不能相互连接。如果没有从L到R的路径,则连接节点(0,0)和(N-1,N-1)。

最初双图完全断开。从原始图中删除边时,我们将相应的边添加到双图中。同时我们更新不相交的数据结构。包含节点L和R的集合连接在一起后立即停止。

此算法只需访问其输入数组A,B和C的元素一次,这使其成为Online algorithm

时间复杂度的最大限制因素是双图节点阵列的初始化时间:O(N 2 )。如果有办法避免这种初始化,我们可以渐进地获得更高效的O(Mα(M))算法。初始化问题有几种方法:

  • 使用this trick在O(1)时间内初始化数组。这给出了O(Mα(M))最坏情况时间算法。但实际上很少有可能在没有初始化的情况下分配内存(出于安全原因)。
  • 初始化一次数组,然后多次使用此算法。这给出了O(Mα(M))摊销时间算法。
  • 使用哈希表存储双图的节点。这给出了O(Mα(M))预期时间算法。这也将空间复杂性提高到O(M)。