AtCoder NoviStepsを埋めてみる(26) 幅優先探索 1Qの続きです。今回も幅優先探索(BFS)です。やや難しめの問題に挑戦します。

E – Transitivity

E – Transitivity

問題の概要

N 頂点 M 辺の単純有向グラフが与えられる。
このグラフが次の条件を満たす状態にするために最小で何回操作を行う必要があるかを求めよ。
(操作)相異なる頂点 x, y であって頂点 x から頂点 y への有向辺が存在しないようなものを選ぶ。そして、頂点 x から頂点 y への有向辺を追加する。
(条件)相異なる頂点 a, b, c すべてについて、頂点 a から頂点 b への有向辺と頂点 b から頂点 c への有向辺がともに存在するならば頂点 a から頂点 c への有向辺も存在する。

この操作を繰り返すことは頂点 x, y が連結ならば頂点 x, y 間に辺を張ることと同じです。このことに気がつけば、すべての頂点についてその頂点からたどり着ける頂点の個数を数えることで、操作が完了したときに存在する辺の総数がわかります。追加すべき辺の最小値はここから最初から存在する辺の数である M を引いた数です。

E – Small d and k

E – Small d and k

問題の概要

N 頂点 M 辺の単純無向グラフがある(各頂点の次数は 3 以下)。
次のクエリに答えよ。
クエリ:頂点 x[i] との距離が k[i] 以下であるような頂点の番号の総和を求めよ。

各頂点の次数は 3 以下であり、調べなければならない距離も 3 以下であることから頂点の集合はそんなに大きくありません。ただしクエリの個数が多いので訪問済みフラグを配列にするとその都度初期化の処理が必要になり TLE してしまいます。なので HashSet で管理します。

D – Swapping Puzzle

D – Swapping Puzzle

問題の概要

H 行 W 列の 2 つのグリッド A, B が与えられる。
グリッド A のある行ととなりの行、またはある列ととなりの列を入れ替えることを繰り返すことで、グリッド A をグリッド B に一致させることが可能かどうかを判定せよ。
一致させることが可能な場合は操作回数の最小値も求めよ。

実際にグリッド A のある行ととなりの行、またはある列ととなりの列を入れ替える操作を繰り返した結果を求め、それを幅優先探索していけばよいです。

E – Avoid Eye Contact

E – Avoid Eye Contact

問題の概要

H 行 W 列のグリッド状に分割されたフィールドがあり、そこにはスタート地点とゴール地点、障害物と人が存在する。
障害物があるマスを通らず、そして人の視線に一度も入らずにゴール地点に到達できるか判定せよ。到達できる場合はそのために必要な移動回数の最小値を求めよ。

人がいるところとその視界を障害物に置き換えます。あとはグリッド上の幅優先探索をしてゴールまでの最短経路長を求めればよいです。

D – Grid Ice Floor

D – Grid Ice Floor

問題の概要

N×M のグリッドがあり、すべてのマスは氷か岩のどちらかである。
この上にプレイヤーがいる。
プレイヤーは移動を開始したら岩のマスにぶつかるまでその方向に移動し続ける。
プレイヤーが通過または上で停止することができる氷の数を求めよ。

プレイヤーは移動を開始したら岩のマスにぶつかるまでその方向に移動し続けるという制約があるので、単純な幅優先探索ではなくプレイヤーの移動方向という情報も持たせて考えなければなりません。頂点倍化の幅優先探索です。

E – Hopscotch Addict

E – Hopscotch Addict

問題の概要

N 頂点 M 辺の単純有向グラフがある。
「『自分の今いる頂点から出ている辺を 1 つ選んで、その辺が接続する頂点に移動する』という操作をちょうど 3 回連続で行なう」を 1 セットとしたとき、頂点 S から頂点 T まで移動することは可能だろうか? 移動可能である場合はセットの最小値も求めよ。

1 セットが 3 回連続の移動なのでその移動は3回中の何回目かがわかるようにして幅優先探索をします。これも頂点倍化の幅優先探索です。

D – Teleport Maze

D – Teleport Maze

問題の概要

H 行 W 列のマス目からなる迷路が与えられる。
. : 空きマス
# : 障害物マス
英小文字(a – z): ワープマス
マス (1, 1) からマス (H, W) へ移動することが可能かどうか判定し、可能ならばそれに必要な最小の合計行動回数を求めよ。

移動が可能なマス同士をつないで幅優先探索で最短経路長を求めるのですが、ワープマスをすべて直接つなごうとすると辺の数が厖大になります。そこで超頂点を導入します。グリッドとは別に 26 個の超頂点を用意し、’a’ であれば ‘a’ の超頂点と ‘a’ のマスを結びます。これだと辺の数を減らすことができるので TLE を回避することができます。

D – People on a Line

D – People on a Line

問題の概要

x 軸上に N 人の人が立っている。人 i の位置は X[i] である。
X[R[i]] – X[L[i]] = D[i] という情報が M 個与えられる。
矛盾しない数列 X が存在するかどうか判定せよ。

ポテンシャル付き Union-Findでも解くことができるが幅優先探索でも解けます。

情報がある頂点間に重みを持つ有向辺を張ります。逆方向であれば重みの符号を反転させます。探索開始点となる頂点の X の値を 0 とし、辺でつながっている頂点に値を設定していきます。構築された有向グラフは連結とは限らないので幅優先探索が完了したら値が設定されていない頂点を探してそこからの幅優先探索を繰り返します。

途中で設定されている値と矛盾があれば”No”が答えです。そうでないなら”Yes”が答えです。

D – うほょじご

D – うほょじご

問題の概要

正の整数 N, M が与えられる。
1 ≦ x ≦ N, 1 ≦ y ≦ M なる整数の組 (x, y) であって、以下の一連の操作を無限に繰り返すことができるものの個数を求めよ。
(操作)
x, y のいずれかが 0 なら、終了する。
x < y なら x を rev(x) で、そうでないなら y を rev(y) で置き換える。
上の操作後、x < y となっていれば y を y – x で、そうでなければ x を x – y で置き換える。
rev(x):x を 10 進表記してできる文字列を反転したもの

1 ≦ x ≦ N, 1 ≦ y ≦ M なるすべての整数の組 (x, y) が (0, ?) または (?, 0) になるか調べていると時間がかかります。問題の制約から操作を繰り返しても 1 ≦ x, y ≦ 999 であることに着目します。

まず 1000 × 1000 個の頂点を用意します。そして操作によって (x1, y1) が (x2, y2) に変化するのであれば 頂点 (1000 * x2 + y2) から頂点 (1000 * x1 + y1) へ辺を張ります(辺を逆向きにするのがポイント)。そして頂点 (1000 * ?) と 頂点 ? から多始点幅優先探索をおこないます。到達できた頂点のなかから 1 ≦ x ≦ N, 1 ≦ y ≦ M である整数の組 (x, y) に相当する頂点の数を数えればよいです。

A70 – Lanterns

A70 – Lanterns

問題の概要

N 個のランプが机の上に置かれている。
操作 i をおこなうとランプ X[i], Y[i], Z[i] の状態を同時に反転させることができる。
すべてのランプの状態を ON にすることができるか判定せよ。
できる場合は操作の最小回数も求めよ。

問題の制約では N ≦ 10 なのでランプがとりうる状態は最大でも 1024 個です。なので幅優先探索をすれば解を得ることができます。

B – パンケーキ (Pancake)

B – パンケーキ (Pancake)

問題の概要

‘A’,’B’,’C’のみからなる N 文字の文字列が Q 回与えられる。
それぞれについて先頭から k 文字だけ反転させる操作を繰り返すことで文字列が昇順ソートされた状態に変更したい。必要な反転操作の回数の最小値を求めよ。

すべての’A’,’B’,’C’のみからなる N 文字の文字列を対象に多始点幅優先探索すればよいです。処理を高速化するために文字列を数値に変換します(文字列を三進数と考えればよい)。すべての文字列から昇順ソートされた文字列への最短経路長を計算しようとすると時間がかかるので、遷移を逆にして昇順ソートされた文字列からそれ以外の文字列への最短経路長を求めます。この前処理があれば Q 回のクエリに対して O(1) で解を返すことができるようになります。

D – テンキー (Tenkey)

D – テンキー (Tenkey)

問題の概要

テンキーがあり、現在選択されている位置は 0 である。
操作 1 と 2 を繰り返すことで入力された値が M で割った余りが R であるようにしたい。操作回数の最小値を求めよ。
操作 1:テンキーの現在選択されている位置を隣に変更する。
操作 2:キーを押下する。この場合はすでに入力されていた数字のすぐ右に新たな数字が入力される。

入力されている値と現在選択されているキーで幅優先探索をすればよいです。新しい数字を追加入力する処理は前の値を 10 倍して M の剰余をとればよいです。

K – ガソリンスタンド

K – ガソリンスタンド

問題の概要

N 個の街と M 本の道路があり、道路は街 U[i] と V[i] を双方向に結んでいる。
K 個の街にはガソリンスタンドがある。
Q 個のクエリに答えよ。
クエリ:街 S[i] を出発し、ガソリンスタンドのある街を 1 つ以上通った後、街 T[i] に行くとき、道を通る回数の最小値を求めよ。

最初にガソリンスタンドから各街への最短経路長を求めておきます。
(ガソリンスタンド i から街 S[i] までの最短経路長 + ガソリンスタンド i から街 T[i] までの最短経路長)の最小値がクエリに対する解となります。