AHC048振り返り
はじめに
MC Digital プログラミングコンテスト(AtCoder Heuristic Contest 047)に参加した。順位は最終結果として400番前半。悪くはないのだが、トップの人とのスコアは1桁違う。
問題
問題を読んでどこから手をつければいいのかが悩ましい。貪欲に...と思っても何を貪欲にすればいいのか思いつかない。ベクトル演算で...と思ったがベクトルの長さ(絵の具を何gだすか)も考慮するとバリエーションが多すぎる。多項式として解けば答えは出せるかもだが、それを1gずつした取り出せない「操作」にマッピングするのが難しそうである。ターゲットの色は
結局、ランダムに操作をして良さそうな操作を選ぶという方法を実装してみることにした。結局最後までこれになったが。
ランダムに操作する方法で解く
パレットをどう表現するか?
操作の中で難しいのが壁を壊したり作ったりすることで「ウェル」を結合したり分割したりする操作の処理。グリッド上での連結を表現するので、UnionFindを使いたい。しかしながらUnionFindは削除ができないので、簡単化する必要がある。具体的には、左か上のマスを最大1つ親に持つ木で管理することにした。こうすると木の「根」は必ず左上にあるので、結合・分割の処理は以下のようになる。
- 結合 : 根の左か上のマスとの間に枝を追加する
- 分割 : 枝を削除する
ウェルの管理方法と、結合, 分割
親が必ず1つなので、広い空間などは表現できないが、今回はウェルの大きさが問題なので制約にはならない。
とりあえずランダムに操作してみる
ランダムに操作していってちゃんと動くのか確認してみた。
ランダムにひたすら操作している状態
やってみると、意外とうまくいっている印象。下の表で上の段が「必要となる色」下の段が「渡した色」なので、結構ちゃんと近い色を渡せていることが分かる。ちなみにseed = 0で 19,216,675点。低いのか高いのかはよくわからない。
不要な操作を消していく
ひたすらランダムな操作をするだけでなんとかなりそうであったが、無駄も多い。上の図のように100色目あたりで、既にパレットは色だらけになっている。また、操作途中で似た色が出てきている場合もありそうだった。そこで、1色を渡すための処理を以下のようにした。
-
回ランダムに操作する。この時途中のウェルの色もすべて保存しておく。M - 途中も含めてすべてのウェルで、必要となる色に最も近いウェルを探す。
- そのウェルを作成するために必要な操作のみを抽出する。
- 上記 1 - 3を時間がある限り繰り返して最も良い操作を見つける
ランダムに操作しつつ最も良い操作を残した場合
分析
K
絵の具の種類問題文をよく読むと必要となる色の決め方には特徴がある。全ての色を使って生成しているのだが、乱数のlogをとってから正規化して色を混ぜている。つまり、全部の絵の具を均等に混ぜるのではなく、特定の絵の具を極端に含む色となっている。
そこで、2つの絵の具を混ぜて、必要となる絵の具に最も近い色を求めてみた。なお、絵の具は 1〜4gのどられかを使うものとした。下図がその結果であるが、絵の具の種類
一方でランダムで操作した場合は、
2種類の絵の具を混ぜて必要な色を生成した時の距離(誤差)の分布
D
絵の具を取り出すコスト絵の具を取り出すコスト
最終的には、
絵の具を取り出すコストとスコアの関係
まとめ
他の方の解説を読んでいると、やはり貪欲的に絵の具の組み合わせからもっともいいものを選んでいるようであった。ただ、今回は必要とされる色がすべての絵の具を混ぜて作成しているので、平均値に収束しがちなランダムな処理でもそこそこの点数がとれたのかな?とは思う。
ところで全然関係ないが、、「ウェル」って何だろう?というのが気になった。wellに「井戸」という意味もあって、そこから「くぼみ」という意味もある..らしい。
Discussion