AtCoder NoviStepsを埋めてみる(6) 再帰全探索 2Qまでの続きです。今回も再帰全探索です。

D – String Equivalence

D – String Equivalence

問題の概要

英小文字からなる 2 つの文字列 s, t の長さが同じであり、任意の i,j に対し次のいずれかが成立するとき同型 であると定義する。
s[i] = s[j] かつ t[i] = t[j]
s[i] ≠ s[j] かつ t[i] ≠ t[j]

文字列 s は以下の条件を満たすとき 標準形 であるといいます。
任意の s と同型な文字列 t に対し、s ≦ t (辞書順での比較)が成立する。
例)zyxzx の標準形は abcac

整数 N が与えられる。長さ N の標準形の文字列をすべて辞書順で出力せよ。

文字追加するとき、
文字列が空のときは ‘a’ を追加
それ以外のとき、’a’ から(文字列のなかにある辞書順でもっとも大きい文字の次の文字)までを追加する処理をすべて試す
をやればよいです。

072 – Loop Railway Plan(★4)

072 – Loop Railway Plan(★4)

問題の概要

H 行 W 列のグリッドがある、各マスは’,’のマスと’#’のマスのどちらかである。
ある’,’のマスを始点とし、始点と終点以外同じマスを通らず、上下左右で隣接する’,’のマスにのみ移動することを繰り返して始点に戻ってくる経路のなかで長さが最大の経路長を求めよ。

D – Dance

D – Dance

問題の概要

2N 人の人で N 組のペアをつくる。
i と j がペアになったときの「相性」は A[i, j] である。
相性のビットごとの排他的論理和を最大化したい。最大値を求めよ。

N の最大値は 8 なので全体で16人いることになります。長さ 16 の順列を全探索することは実行時間制限以内にはできないので他の方法を考えます。

N 個のペアにわけるとして各人が問題になるのはどのペアに属するかではなく、自分とペアになるのはどの人なのかということです。

ペアの最初の人はまだ相手が決まっていない人であれば誰を選んでもよいです。なのでまだ相手が決まっていない番号が一番小さい人を選びます。その人の相手は残りのなかから全探索します。この方法なら 8 ペアであればすべての組み合わせを全探索することができます。

D – Peaceful Teams

D – Peaceful Teams

問題の概要

N 人の選手がいて、そのなかで A[i] 番目の選手と B[i] 番目の選手は相性が悪い。
この選手たちを T 個のチームに分ける。
どの選手もちょうど一つのチームに属さなければならず、どのチームにも少なくとも一人の選手が属さなければならない。
また同じチームに相性が悪い選手同士がいてはならない。
この条件を満たすチーム分けの方法は何通りあるか求めよ。

各選手がどのチームに属するかを決めます。このときにD – String Equivalence にある標準形をつくったときのような処理をおこないます。標準形のなかで要素の種類が T 個ある場合、選手たちのチーム分けができたことになります。

あとは相性が悪い選手が同一チームでないチーム分けになっているものだけを数えます。

D – Domino Covering XOR

D – Domino Covering XOR

H 行 W 列のマス目があり、マス (i, j) には非負整数 A[i, j] が書かれている。
このマス目にドミノを 0 個以上置く。
1 つのドミノは隣り合う 2 つのマスを覆うように置くことができるが、同じマスに対して複数のドミノを置くことはできない。
ドミノが置かれていないマスに書かれた整数すべてのビットごとの排他的論理和を置き方のスコアと定義する。
ドミノの置き方のスコアとしてありうる最大値を求めよ。

ドミノは縦に置くか横に置くかのどちらかです。そこですべての(i, j)において、ドミノを (i, j), (i, j + 1) と置くか、(i, j), (i + 1, j) と置くか、置かないかを決めます。処理を高速にするためにはドミノを置く置かないを bit で管理するようにし、次のマスに移動するときは再帰呼び出しでドミノの状態を渡していきます。

D – Hanjo

D – Hanjo

問題の概要

H 行 W 列のグリッドと A 個の 1 × 2 の大きさのタイル、B 個の 1 × 1 の大きさのタイルがある。
グリッド上にタイルが重なったり隙間ができないように敷き詰めた場合、置き方は何通りあるだろうか?

D – Domino Covering XOR と同じような方法で解けますが、置き方を数え上げるときにダブルカウントしないように注意する必要があります。

E – Maximize XOR

E – Maximize XOR

問題の概要

長さ N の非負整数列 A および整数 K が与えられる。ここで二項係数 nCk は 10^6 以下であることが保証される。
A から異なる K 項を選ぶとき、選んだ K 個の数の総 XOR としてあり得る最大値を求めよ。

単純にこれまでやってきたような再帰全探索をしようとすると TLE します。以下はダメなコードです。N = 1000, K = 998 のようなテストケースがあると通りません。

打開策ですが、K が N の半分よりも大きいときは K 個取る方法ではなく、N – K 個を取らない方法を考えます。これだと実行時間制限をオーバーすることなく AC することができます。

D – ABC Puzzle

D – ABC Puzzle

問題の概要

整数 N と ‘A’, ‘B’, ‘C’ からなる長さ N の文字列 R,C が与えられる。

N×N のマス目の各マスに A, B, C のうち高々 1 文字を書き込んだときに、以下の条件を全て満たすことが可能であるか判定し、可能であれば書き込み方を 1 つ出力せよ。

各行 / 各列 に A, B, C がちょうど 1 個ずつ含まれる
i 行目に書かれた文字の中で最も左にある文字は R の i 文字目と一致する
i 列目に書かれた文字の中で最も上にある文字は C の i 文字目と一致する

全パターン調べましょう。

まず順列を生成して “ABC..” の並び順をすべて生成します。N = 3 なら 6 通り、N = 4 なら 24 とおり、N = 5 なら 60 通りです。

あとは再帰全探索でこれらのなかから N 個抜き出してグリッドを生成して条件を満たしているものを解として出力すればいいのですが、本当に全部調べようとすると実行時間制限にひっかかってしまいます。

なので、条件に反するものであれば再帰処理をしないで計算量を減らしています。

D – Stone XOR

D – Stone XOR

問題の概要

N 個の袋があり、袋 i には A[i] 個の石が入っている。
「2 つの袋 A, B を選び、袋 A に入っている石を すべて 袋 B に入れる」という操作を好きなだけ(0 回でもよい)繰り返す。
このとき「すべての袋に入っている石の数の排他的論理和」としてあり得るものが何個あるか求めよ。

「2 つの袋 A, B を選び、袋 A に入っている石を すべて 袋 B に入れる」という操作は A と B を同じグループにするということを意味しています。

なのでグループ分けを全パターン試します。

D – Peaceful Teamsと似ていますが、この問題はグループの個数に縛りがない点が異なっています。

あとは XOR を計算してその種類数をカウントするだけと言いたいのですが、long 型で HashSet を使おうとするとハッシュが衝突して計算時間が伸びてしまい TLE するというケースがあります。なので 32 で割ったときの剰余で別のオブジェクトに格納するようにしています。

D – RGB Coloring 2

D – RGB Coloring 2

問題の概要

N 頂点 M 辺の単純無向グラフが与えられる。
辺 i は頂点 A[i] と頂点 B[i] を結んでいる。
このグラフの各頂点を赤、緑、青の 3 色のいずれかで塗る方法であって、以下の条件を満たすものの数を求めよ。
辺で直接結ばれている 2 頂点は必ず異なる色で塗られている。
使われない色があってもよい。

N の最大値が 20 なので3^N 通りの塗り方を全探索する方法では実行時間制限に間に合わせることができません。

しかし、全探索の対象を 3^N 通りではなく 3 × 2^(N – 1) に減らすことができます。

なぜならある頂点 x の色を決めた時、x と辺で繋がっている頂点の色の探索候補は 2 通りしかありません。グラフが連結なら 3 × 2^(N – 1) だけ探索すればよいし、連結でないなら各連結成分で同様の処理をおこない、部分解の総積が解となります。

連結成分に分解して各グループのある頂点を起点に色をつけていきます。隣の頂点と同じ色で塗ろうとしている場合以外は再帰処理を繰り返してすべての頂点に色をつけることができたものを数え上げます。

着色する順番を適当に決めていると TLE する原因となります。

与えられたグラフがスターグラフ(中心から放射状に枝が伸びているグラフ)を考えることにします。中心の頂点番号が 20、それ以外の葉にあたる頂点の番号が 1 ~ 19 であった場合、葉は互いに独立なので全部 3 通り探索しなければなりません。これだと計算量が O(3^(N – 1) × 2)となり、N = 20 の場合は 3^19 = 1,162,261,467 であることを考えると TLE 必至です。

この問題は探索する頂点を DFS木順 に並べることで回避できます。このように並べ直すことで次の探索対象は必ず「すでに塗られた隣接頂点」を持つからです。これによって計算量を O(3 × 2^(N – 1)) に落とすことができます。

連結成分に分解する処理は ライブラリ ac-library-csharp の Dsu クラスを使用しています。

参考: ac-library-csharpを使ってみる

E – Red Polyomino

E – Red Polyomino

問題の概要

N 行 N 列のグリッドが与えられる。
上から i 番目、左から j 番目のマスは、S[i][j] で表され、これが # なら黒く塗られており、. なら白く塗られている。
白く塗られたマスのうち、ちょうど K 個のマスを選んで赤く塗りたい。
赤く塗られたマスが連結である塗り方は何通りあるだろうか?

N^2 個のマスから K 個選ぶ方法は (N^2)C(K) 通りあり、N = 8, K = 8 のときは 64C8 = 4,426,165,368 となり、TLE 必至です。

しかし赤マス同士が連結という条件から、条件を満たす選び方はそれより少ないです。入出力例 3 から 最大で 64678 しかないことがわかります。

最初に赤く塗るマスを決め、あとはすでに赤く塗られているマスから上下左右に辿って到達できるものだけを塗り続けるという再帰処理をして全探索します。