(ブログ用)codeforces #400 d. the door problem

48
Codeforces #400 D. The Door Problem satanic @satanic0258

Upload: satanic

Post on 11-Apr-2017

88 views

Category:

Education


2 download

TRANSCRIPT

Page 1: (ブログ用)Codeforces #400 D. The Door Problem

Codeforces #400D. The Door

Problemsatanic @satanic0258

Page 2: (ブログ用)Codeforces #400 D. The Door Problem

🔓🔒🔓

A B C

以下の例(サンプル2)を例にとって解説していきます。なお今後、下の図において、・黒は未決定の状態・橙はオンにした状態・青はオフにした状態を表します。

a

c

b

Page 3: (ブログ用)Codeforces #400 D. The Door Problem

🔓🔒🔓

A B C

まず A を押した場合、 A は全てのドアに繋がるため、全てのドアの状態が反転します。

a

c

b初期状態

Page 4: (ブログ用)Codeforces #400 D. The Door Problem

🔒🔓🔒

A B C

まず A を押した場合、 A は全てのドアに繋がるため、全てのドアの状態が反転します。

a

c

b初期状態

Page 5: (ブログ用)Codeforces #400 D. The Door Problem

🔒🔓🔒

A B C

まず A を押した場合、 A は全てのドアに繋がるため、全てのドアの状態が反転します。すると、 a はオフになってしまいました。a をオンにするには C もオンである必要があります。

a

c

b初期状態

Page 6: (ブログ用)Codeforces #400 D. The Door Problem

🔒🔓🔒

A B C

まず A を押した場合、 A は全てのドアに繋がるため、全てのドアの状態が反転します。すると、 a はオフになってしまいました。a をオンにするには C もオンである必要があります。C をオンにしました。それに伴って、ドアの状態は…

a

c

b初期状態

Page 7: (ブログ用)Codeforces #400 D. The Door Problem

🔓🔓🔓

A B C

まず A を押した場合、 A は全てのドアに繋がるため、全てのドアの状態が反転します。すると、 a はオフになってしまいました。a をオンにするには C もオンである必要があります。C をオンにしました。それに伴って、ドアの状態は次のようになります。

a

c

b初期状態

Page 8: (ブログ用)Codeforces #400 D. The Door Problem

🔓🔓🔓

A B C

今、考慮していない c の状態も変わりましたが、結果的に c も開いている状態になったのでよしとします。

a

c

b初期状態

Page 9: (ブログ用)Codeforces #400 D. The Door Problem

🔓🔓🔓

A B C

これで、全てのドアが開いている状態になりました。B の状態がまだ決まっていませんが、b は片方が決まっていて開いているため、b に繋がっている B はオフとなります。

a

c

b初期状態

Page 10: (ブログ用)Codeforces #400 D. The Door Problem

🔓🔓🔓

A B C

これで、全てのドアが開いている状態になりました。B の状態がまだ決まっていませんが、b は片方が決まっていて開いているため、b に繋がっている B はオフとなります。よって、ドアを全て開いた状態にするスイッチの組み合わせがあることが分かりました。

a

c

b初期状態

Page 11: (ブログ用)Codeforces #400 D. The Door Problem

この問題を、グラフ上で解いてみましょう。

初期状態

Page 12: (ブログ用)Codeforces #400 D. The Door Problem

この問題を、グラフ上で解いてみましょう。2-SAT をグラフに帰着するとき、オン / オフの状態を決めるものそれぞれについて、オンの頂点とオフの頂点を作ります。

初期状態A

A

B

B

C

C

Page 13: (ブログ用)Codeforces #400 D. The Door Problem

この問題を、グラフ上で解いてみましょう。2-SAT をグラフに帰着するとき、オン / オフの状態を決めるものそれぞれについて、オンの頂点とオフの頂点を作ります。ここで、オンの頂点はそのまま、オフの頂点には上にバーを付けることにします。

初期状態A

A

B

B

C

C

オン→オフ→

Page 14: (ブログ用)Codeforces #400 D. The Door Problem

では、このグラフに辺を張っていきます。

初期状態A

A

B

B

C

C

オン→オフ→

Page 15: (ブログ用)Codeforces #400 D. The Door Problem

では、このグラフに辺を張っていきます。まず A をオンにすると、 a,c を介して繋がる C もオンにする必要がありました。そのため、 A→C と辺を張ります。

初期状態A

A

B

B

C

C

オン→オフ→

Page 16: (ブログ用)Codeforces #400 D. The Door Problem

では、このグラフに辺を張っていきます。まず A をオンにすると、 a,c を介して繋がる C もオンにする必要がありました。そのため、 A→C と辺を張ります。また、 b を介して繋がる B はオフにする必要がありました。そのため、 A→B と辺を張ります。

初期状態A

A

B

B

C

C

オン→オフ→

Page 17: (ブログ用)Codeforces #400 D. The Door Problem

同様に、各頂点について辺を張っていきます。

初期状態A

A

B

B

C

C

オン→オフ→

Page 18: (ブログ用)Codeforces #400 D. The Door Problem

同様に、各頂点について辺を張っていきます。B をオンにすると、 A はオフにする必要があります。従って、 B→A と辺を張ります。

初期状態A

A

B

B

C

C

オン→オフ→

Page 19: (ブログ用)Codeforces #400 D. The Door Problem

同様に、各頂点について辺を張っていきます。B をオンにすると、 A はオフにする必要があります。従って、 B→A と辺を張ります。C をオンにすると、 A はオンにする必要があります。しかし、これについては既に調べてあるため、わざわざ二重に辺を張る必要はありません。

初期状態A

A

B

B

C

C

オン→オフ→

Page 20: (ブログ用)Codeforces #400 D. The Door Problem

A をオフにすると、 C もオフにする必要があります。従って、 A→C と辺を張ります。

初期状態A

A

B

B

C

C

オン→オフ→

Page 21: (ブログ用)Codeforces #400 D. The Door Problem

A をオフにすると、 C もオフにする必要があります。従って、 A→C と辺を張ります。B をオフにした場合、 C をオフにした場合については、既に調べられている状態になっているため、グラフ上に変化はありません。

初期状態A

A

B

B

C

C

オン→オフ→

Page 22: (ブログ用)Codeforces #400 D. The Door Problem

こうして全ての辺を張ることが出来ました。

初期状態A

A

B

B

C

C

オン→オフ→

Page 23: (ブログ用)Codeforces #400 D. The Door Problem

こうして全ての辺を張ることが出来ました。このグラフを見ると、つじつまが合うようなスイッチの組み合わせは全て同じ連結成分になっており、逆に矛盾が発生するような頂点同士は連結になっていないことが分かります。

初期状態A

A

B

B

C

C

オン→オフ→

Page 24: (ブログ用)Codeforces #400 D. The Door Problem

こうして全ての辺を張ることが出来ました。このグラフを見ると、つじつまが合うようなスイッチの組み合わせは全て同じ連結成分になっており、逆に矛盾が発生するような頂点同士は連結になっていないことが分かります。では、ある頂点と連結になっている頂点を全て抜き出せばそれが正しい組み合わせとなるのでしょうか?

初期状態A

A

B

B

C

C

オン→オフ→

Page 25: (ブログ用)Codeforces #400 D. The Door Problem

そうとは限りません。右の図のように、連結成分の中には「 A がオンならば A をオフにしなければならない」といったおかしな部分が出ることがあります。

初期状態

A

A

A

A

B

B

C

C

オン→オフ→

Page 26: (ブログ用)Codeforces #400 D. The Door Problem

そうとは限りません。右の図のように、連結成分の中には「 A がオンならば A をオフにしなければならない」といったおかしな部分が出ることがあります。逆に言えば、グラフにこのような矛盾が無ければ正しいスイッチの組み合わせがあるとわかります。

初期状態

A

A

A

A

B

B

C

C

オン→オフ→

Page 27: (ブログ用)Codeforces #400 D. The Door Problem

今回の例では、 A と A 、 B と B 、 C と C 、と全ての頂点で、別々の連結成分に属していることが分かります。

初期状態A

A

B

B

C

C

オン→オフ→

Page 28: (ブログ用)Codeforces #400 D. The Door Problem

今回の例では、 A と A 、 B と B 、 C と C 、と全ての頂点で、別々の連結成分に属していることが分かります。よって、グラフからこの例では正しいスイッチの組み合わせが存在することが分かりました。

初期状態A

A

B

B

C

C

オン→オフ→

Page 29: (ブログ用)Codeforces #400 D. The Door Problem

🔓🔒🔓

AB

C

では、今度は以下の例(サンプル1)について見ていきます。

a

c

b初期状態

Page 30: (ブログ用)Codeforces #400 D. The Door Problem

では、今度は以下の例(サンプル1)について見ていきます。スイッチ数は先ほどと同じなため、グラフの初期状態も同じとなります。

初期状態A

A

B

B

C

C

オン→オフ→

Page 31: (ブログ用)Codeforces #400 D. The Door Problem

まず A をオンにした場合について考えます。A は a を介して B に、また c を介して C に繋がっています。

初期状態A

A

B

B

C

C

オン→オフ→

Page 32: (ブログ用)Codeforces #400 D. The Door Problem

まず A をオンにした場合について考えます。A は a を介して B に、また c を介して C に繋がっています。従って、 A をオンにすると B と C もオンにする必要があるため、A→B 、 A→C と辺を張ります。

初期状態A

A

B

B

C

C

オン→オフ→

Page 33: (ブログ用)Codeforces #400 D. The Door Problem

まず A をオンにした場合について考えます。A は a を介して B に、また c を介して C に繋がっています。従って、 A をオンにすると B と C もオンにする必要があるため、A→B 、 A→C と辺を張ります。同様に、 B をオンにすると A はオンに、 C はオフにする必要があるため、 B→A 、 B→C と辺を張ります。( A-B 間は既に辺が張ってあるため実際には張りません)

初期状態A

A

B

B

C

C

オン→オフ→

Page 34: (ブログ用)Codeforces #400 D. The Door Problem

同様に、

初期状態A

A

B

B

C

C

オン→オフ→

Page 35: (ブログ用)Codeforces #400 D. The Door Problem

同様に、 C 、

初期状態A

A

B

B

C

C

オン→オフ→

Page 36: (ブログ用)Codeforces #400 D. The Door Problem

同様に、 C 、 A 、

初期状態A

A

B

B

C

C

オン→オフ→

Page 37: (ブログ用)Codeforces #400 D. The Door Problem

同様に、 C 、 A 、 B 、

初期状態A

A

B

B

C

C

オン→オフ→

Page 38: (ブログ用)Codeforces #400 D. The Door Problem

同様に、 C 、 A 、 B 、 C についても辺を張ります。

初期状態A

A

B

B

C

C

オン→オフ→

Page 39: (ブログ用)Codeforces #400 D. The Door Problem

同様に、 C 、 A 、 B 、 C についても辺を張ります。こうして、全ての辺を張ることが出来ました。では、どの頂点が連結になっているでしょうか。

初期状態A

A

B

B

C

C

オン→オフ→

Page 40: (ブログ用)Codeforces #400 D. The Door Problem

同様に、 C 、 A 、 B 、 C についても辺を張ります。こうして、全ての辺を張ることが出来ました。では、どの頂点が連結になっているでしょうか。ある頂点から初めて辺を順に辿っていくと分かりますが、この例では、全ての頂点が連結となっています。

初期状態A

A

B

B

C

C

オン→オフ→

Page 41: (ブログ用)Codeforces #400 D. The Door Problem

特に、 A と A が同じ連結成分に属しているため、この例では正しいスイッチの組み合わせが存在しないことが分かります。

初期状態A

A

B

B

C

C

オン→オフ→

Page 42: (ブログ用)Codeforces #400 D. The Door Problem

特に、 A と A が同じ連結成分に属しているため、この例では正しいスイッチの組み合わせが存在しないことが分かります。このように、グラフに帰着してこの問題を解くことが出来ます。

初期状態A

A

B

B

C

C

オン→オフ→

Page 43: (ブログ用)Codeforces #400 D. The Door Problem

実際にプログラムを実装する際には、・グラフに辺を追加する・ある2頂点が連結であるかを調べるというクエリをこなすデータ構造である、素集合森(通称 Union-Find )を使うと良いでしょう。

初期状態A

A

B

B

C

C

オン→オフ→

Page 44: (ブログ用)Codeforces #400 D. The Door Problem
Page 45: (ブログ用)Codeforces #400 D. The Door Problem

その後、 A と A が同じ連結成分に属しているか否かを調べることで組み合わせの存在を調べます。

Page 46: (ブログ用)Codeforces #400 D. The Door Problem

※ 注意※しかし、この問題で現れる論理式は、・同値 ( ⇔ )…両方押すか押さないか・排他的論理和( XOR )…どちらか片方だけ押すの積となっています。

Page 47: (ブログ用)Codeforces #400 D. The Door Problem
Page 48: (ブログ用)Codeforces #400 D. The Door Problem

おわり