🌳

[ARC111 B] Reversible Cards

2024/02/07に公開

https://atcoder.jp/contests/arc111/tasks/arc111_b

普通の木か見分ける問題。

問題を理解する

ひとことで言えば、

  • カード毎に裏表を適当に選んだときの最大色数は?

になる。たとえば次の2枚のカードがあったとき、

「白 → 白」よりも「白 → 黒」を選択したときのほうが色数が増える。したがって答えは 2 (色) になる。

他のパターンで考える

4枚のカードを順に見ていく。

考え方 色数
とりあえず片方を選択してみる +1
1枚目と同じカードなので反対の色を選択する +1
また同じ。どっちを選択しても色数が増えないので飛ばす
どっちも初登場なので、どちらかを選択して1色増える +1

答え → 3

グラフ化する

上のパターンを元に裏表を辺にしたグラフをイメージする。その際に辺の矢印が選択した方を指すようにする。

選択した方を矢印で指すようにしたのであたりまえだが、こうしてできたグラフは「矢印の数 = 色数」になっている。

そして「白黒」の連結成分に着目すると、同じ「白黒」だけを使ったカードをこれ以上追加しようとしても矢印が増やせない。したがって、辺が多すぎる木の色数は「節の数」になる。

一方「赤青」の連結成分は無駄のない普通の木である。ここで仮に辺を減らせないか考えてみるが、辺を無くすとこの木自体がなくなってしまう。したがって、普通の木の色数は「節の数 - 1」になる。

種類 色数
辺が多すぎる木 節の数
普通の木 節の数 - 1

ここまでくれば、どちらの木かを見分けるだけの問題だと気づく。

見分け方

↓ グラフと

↓ 素集合森を

比べる。

グラフでの辺が 1 つの「赤青」は素集合森でも 1 つなので「普通の木」だとわかる。一方、辺が 3 つの「白黒」は素集合森では 1 つなので「辺が多すぎる木」だとわかる。

連結成分 種類
白黒 辺が多すぎる木
赤青 普通の木

考え方の最適化

「連結成分の種類」を調べてから「節の数」または「節の数 - 1」を色数とする二段階の考え方は、単に「グラフとしてみたときの辺の数」と「素集合森での節の数」の小さい方を色数とする考えに置き換えることができる。

これは「グラフとしてみたときの辺の数」が多すぎたときだけ「素集合森での節の数」で制限するイメージになる。

コード (AC)

N = gets.to_i                                              # => 12
XY = N.times.collect { gets.split.collect(&:to_i) }        # => [[5, 2], [5, 6], [1, 2], [9, 7], [2, 7], [5, 5], [4, 2], [6, 7], [2, 2], [7, 8], [9, 7], [1, 8]]
ds = DisjointSet[XY]
p ds.groups.keys.sum { |e| [ds.edge(e), ds.size(e)].min }  # => 8

参考

Discussion