A - Don't Detect Cycle Editorial
by
Astral__
部分点
まず、もし条件を満たす辺の追加順が存在するならば、「最後に追加しても、その回で条件を違反しない」ような辺が \(1\) つ以上存在します。
そして、そのような辺について、今追加順が未定の辺の中で最後に追加すると決定してしまって良いです。これは、後に追加した辺が前に追加する辺に制約を課す事が無い事、及びその辺の追加で条件が違反されない事より従います。
そして、一度最後に追加すると決定してしまった辺は先述の通り、前に追加する辺に影響を与えないので元々初めから存在しなかった物として考えて良いです。よって、この”辺の削除”を繰り返す事によって解を得ます。
最後に追加して良い辺は全探索で探す事にします。計算量は、辺の削除を \(M\) 回行い、その中で最後に追加する辺を全探索するのに平均 \(\frac{M}{2}\) 回程度のループを回し、そのループの中で条件を違反しないかを判定するのに \(O(N + M)\) の計算量がかかる(例えば、lowlinkを用いれば良いです。「頂点 \(v\) を含むサイクルが存在する事」は、「 \(v\) に直接繋がる辺であって、橋で無いものが存在する」事と同値な事を用います。)ので、総じて計算量 \(O(M^2(M + N))\) で本問題を解く事ができました。
満点
まず、最終的なグラフに置いてどのようなサイクルにも含まれない辺、つまり橋を考えます。
実は、最終的なグラフにおける橋は今追加順が未定の辺の中で最初に追加するとして良い事が示せます。またさらに、そう決定したら以降初めから存在しなかった物として考えて良いです。
追加順が未定の辺の中で最初に追加するとして良い事
最終的なグラフにおいてどのようなサイクルにも含まれない辺は、前に追加した辺から制約を受ける事はあっても、後に追加する辺に制約を課す事はない。
また、最初に追加したとしても、その辺が制約を違反する事はない。
よって、条件を満たす辺の追加順が存在するならば、そのような辺は最初にまとめて追加するとした新たな追加順も条件を満たす。
以降、初めから存在しなかったとして考えて良い事
かつ、このように最初に追加した辺はサイクルの成立に関わらないので、後に追加する辺に制約を課す事はない。
以降考えるグラフでは、全ての辺が最終的なグラフにおいてなんらかのサイクルに属しているとします。そういえば、部分点において、”最後に追加しても良い辺” は全探索で探していました。これを、全探索せずに取得できないでしょうか?
ここで、辺 \(e = (u, v)\) であって、最終的なグラフにおける両端の頂点の次数が共に \(2\) 以下の辺に注目します。
この時、そのような辺 \(e\) は今追加順が未定の辺の中で最後に追加するとして良い事が示せます。またさらに、そう決定したら以降初めから存在しなかった物として考えて良いです。
辺 \(e\) を最後に追加する事によって、制約が違反されない事
辺 \(e\) が追加できない状況を考える。
それは 辺 \(e\) を取り除いたグラフにおいて、 \(u\) 或いは \(v\) が既にサイクルに含まれている状況である。
しかし、辺 \(e\) を取り除いたグラフにおいて、 \(u\) , 及び \(v\) の次数は高々 \(1\) であるから、 \(u\) 或いは \(v\) が既にサイクルに含まれていることはあり得ない。
よって、 辺 \(e\) の追加によって制約が違反される事はない。
この両方の操作を出来る限り繰り返します。 最終的に、追加する予定の辺が \(0\) 本になった場合、自明に条件を満たす辺の追加順が存在します。
逆に、予定の辺が \(0\) 本にならない場合を考えます。 つまり、任意の辺はサイクルに含まれていて、かつ両端の頂点の次数のうち少なくとも大きい方が \(2\) を超過しているグラフを考えます。この時、そのようなグラフにおいて条件を満たす辺の追加順は存在しない事が示せます。
用語の設定
辺の集合に対して、最後に追加する辺を任意に取り、辺 \(e' = (u', v')\) と置く。及び、辺 \(e'\) だけを取り除いたグラフを \(g\) と置く。
\(u', v'\)の対称性及びグラフに対する仮定より、グラフ \(g\) において、 \(v'\) の次数 \(\ge 2\) として良い。
ここで、 \(g\) において \(v'\)に直接繋がっている頂点から任意に \(2\) 頂点選び、それぞれ \(a, b\) と置く。
背理法による証明
\(v'\) が \(g\) においてサイクルに含まれていないと仮定する。
辺 \(e'\) を追加したグラフにおいて、 辺 \((a, v')\) がサイクルに含まれる辺であることから、 \(g\) に 辺 \(e'\) を追加したグラフ上には辺 \((a, v')\) を用いない \(v'\) —> \(a\) の頂点素・辺素なパスが存在する。
しかし、辺 \(e'\) を追加する直前に \(v'\) がサイクルに含まれないことにより、辺 \(e'\) を追加する前段階でははそのような \(v'\) —> \(a\) のパスは存在しない。
よって、最終的なグラフにおけるそのような \(v'\) —> \(a\) のパスは 辺 \(e'\) を通る。
つまり、グラフ \(g\) において \(u'\) —> \(a\) の頂点・辺素なパスであって頂点 \(v'\) を含まないものが既に存在する。
同様に、 \(u'\) —> \(b\) の頂点・辺素かつ頂点 \(v'\) を含まないパスも存在する。
それを合体させる事で、 \(a\) —> \(u'\) —> \(b\) のパスをグラフ \(g\) 上に得る。
及び、 \(a\) —> \(u'\) —> \(b\) のパスにおいて、 \(2\) 回以上登場する辺や頂点が存在する限りその間を消すことで、最終的に \(a\) —> \(b\) の頂点・辺素かつ頂点 \(v'\) を含まないパスを得られる。
そして、このパスを用いて \(v'\) -> \(a\) —> \(b\) -> \(v'\) のサイクルが \(g\) 上に得られる。 つまり、 \(v'\) が \(g\) 上サイクルに含まれていないという仮定は矛盾である。
この考えは、そのまま構築になります。
具体的には、グラフの橋の列挙にlowlink等の適切なアルゴリズムを用いることで、計算量 \(O(M(N + M))\) で解く事が出来ます。
実装例(C++)
おまけ: 構築が正しいかの判定について、計算量 \(o(M(N+M))\) で解く事ができます。
posted:
last update: