3

次の図に示すように、N×Nの正方形のメッシュ型のワイヤーグリッドがあります。グリッドのノードはポイント(X、Y)にあり、XとYは0からN-1までの整数です。電流は、(0、0)と(N-1、N-1)のノード間でグリッドを流れます。 ここに画像の説明を入力してください

最初は、すべてのワイヤーが電流を流しますが、ワイヤーは1秒に1回の割合で燃え尽きます。バーンアウトは、それぞれサイズMの整数の3つのゼロインデックス配列A、B、およびCによって記述されます。各瞬間T(0≤T<M)について、T番目の秒でノード間のワイヤ(A [T ]、B [T])および:

    (A[T], B[T] + 1), if C[T] = 0 or
    (A[T] + 1, B[T]), if C[T] = 1

燃え尽きる。アレイが既存のワイヤを記述し、ワイヤが2回以上燃え尽きることはないと想定できます。あなたの仕事は、電流が(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
A 1 = 1 B 1 = 1 C 1 = 1
A 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)のノード間に接続がないため、関数は8を返すはずです。この状況を次の図に示します。

ここに画像の説明を入力してください

N = 4、M = 1、および次の配列が与えられます。

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

1本のワイヤーを焼き尽くしても(0、0)と(N-1、N-1)のノード間の接続を切断できないため、関数は-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).
4

1 に答える 1

5

ワイヤーの完全なグリッドを構築します。次に、最初のM/2ワイヤーを破壊します。深さ優先探索で接続を確認します。まだ接続されている場合は、M/4以上のワイヤーを破壊します。そうでない場合は、M/4で最後に破壊されたワイヤーを復元します。適切なTが見つかるまで、この二分探索を続けます。

時間計算量は、深さ優先探索の数O(log M)<= O(log N)と各深さ優先探索の複雑さO(N 2)によって決定されます。


以前の結果は、素集合データ構造で改善される可能性があります。

ワイヤーの完全なグリッドを構築します。次に、アレイA、B、およびCの指示に従ってMワイヤを破棄します。グリッドの残りの連結成分を互いに素なデータ構造に追加します。

次に、これらのアレイの最後の要素から始めて、最初の要素に至るまで、ワイヤを順番に復元します。これを行いながら、素集合構造に残っている集合の和集合を見つけます。ノード(0、0)と(N-1、N-1)を含むセットが結合されたときに停止します。

素集合データ構造がランクおよびパス圧縮アプローチによる和集合を使用する場合、アルゴリズム全体の時間計算量はO(N2α(N))です。ここで、αは逆アッカーマン関数です。これは実質的にO(N 2 )と同じくらい良いです。


ワイヤーの元のグリッドに対して双対グラフを使用すると、以前の結果が改善される可能性があります。双対グラフのノードは元のグラフの面に対応し、双対グラフの各エッジは元のグラフの対応するエッジと交差します。2つの追加ノードが必要になります。ノードLは双対グラフのすべての上部と左側のノードに接続され、ノードRはすべての下部と右側のノードに接続されます。

                                                    双対グラフ

この双対グラフにLからRへのパスが含まれている場合、ノード(0、0)と(N-1、N-1)を相互に接続することはできません。LからRへのパスがない場合、ノード(0、0)と(N-1、N-1)が接続されます。

最初、双対グラフは完全に切断されています。元のグラフからエッジを削除しながら、対応するエッジを双対グラフに追加します。同時に、素集合データ構造を更新します。ノードLとRを含むセットが結合されたらすぐに停止します。

このアルゴリズムは、入力配列A、B、およびCの要素に1回だけアクセスする必要があるため、オンラインアルゴリズムになります。

時間計算量の最も制限的な要因は、双対グラフのノードの配列の初期化時間O(N 2)です。この初期化を回避する方法があれば、漸近的により効率的なO(Mα(M))アルゴリズムが得られます。初期化の問題にはいくつかのアプローチがあります。

  • このトリックを使用して、O(1)時間で配列を初期化します。これにより、O(Mα(M))の最悪の場合の時間アルゴリズムが得られます。ただし、実際には、メモリを初期化せずに割り当てることはめったにありません(セキュリティ上の理由から)。
  • アレイを1回初期化してから、このアルゴリズムを何度も使用します。これにより、O(Mα(M))の償却時間アルゴリズムが得られます。
  • ハッシュテーブルを使用して、双対グラフのノードを格納します。これにより、O(Mα(M))の予想時間アルゴリズムが得られます。また、これによりスペースの複雑さがO(M)に向上します。
于 2012-12-07T19:27:50.453 に答える