2021年9月12日日曜日

日本橋ハーフマラソン 2021 増刊号 A - 農場王X

評価関数を作ってビームサーチした。

前提

収穫機を買うのをどこでやめるか問題はしばらく考えずに、収穫機も資金に換算したスコアで物事を考えることにした。

評価関数

収穫機を設置/撤去する場所の持つべき望ましい性質を列挙して、それらの組み合わせで評価関数を作る。評価はマス毎に行い、価値の高いマスに収穫機を設置して価値の低いマスから収穫機を撤去する貪欲法を前提とする。また、理想的には、収穫機のあるマスの価値の総和を取ると盤面の価値になっていてほしい。

以下の評価関数に従って貪欲法をするとして、収穫機を買うのを止めるタイミングを全探索すると2.6億程度のスコアになった。

マスの価値

基本的には設定の通り、マスを覆う連結成分のサイズ×野菜の価値がそのマスの価値と考えるとよさそう。まだ出現していない野菜については時刻が離れると価値が指数的に下がるとして調整した。時刻の値は野菜の出現日と消失日の2種類があるが、消失日に従って下がるとしたほうがよかった。

また、既に出現している野菜についても、やはり消失日が遠いと価値が指数的に下がるとしたほうがスコアがよいようだった。

マスの価値の伝搬

現在か近い未来に価値の高い野菜が生えるマスの周辺は価値が高いと考えられる。ただ、具体的に価値をどう伝搬するかが問題だった。周辺にどれだけ野菜が多かろうと1ターンで覆えるマスは1つだけなので、野菜が多いエリアを過大評価しないようにする必要がある。

いろいろ試した結果、最大連結成分からの最短経路DAGを作って、その逆順に各頂点vvmaxpvの親頂点(pの価値)\max_{pはvの親頂点}(pの価値)に減衰率を掛けたものを加算していくことにした。

  • これだと距離について指数的に価値が減っていくことになるけれど、価値が3倍なら3ターン掛けてでもいくべき、と考えると反比例で減っていくほうが自然に思える。ただ、こちらは高速な表現ができなかった。
  • 最大連結成分から到達する前に消失してしまう野菜の価値は伝搬しないようにする。

連結していることの価値

収穫機の連結性は維持したい。これを収穫機のないマスについて言い換えると、連結成分の隣は価値が大きい。収穫機のあるマスについて言い換えると、連結成分の関節点は非関節点より価値が大きい。

収穫機が数個のうちはいくつかの連結成分に分離して遠くの野菜を取りに行く可能性も考慮するつもりだったが、試してみるとそれで得られる利益がほぼないことがわかったので、最終的にはひとつの連結成分を伸縮することを前提とした方針に変えた。つまり、評価関数に含めるのではなく、収穫機を撤去するマスは非関節点で、収穫機を置くマスは連結成分の隣とした。

また、下記のビームサーチをする際には収穫機のあるマスの価値の総和を盤面の価値としたが、この時は非関節点が多い配置のほうが(次の撤去候補が多いぶん)やや良いという考えに基づいて、非関節点の評価値に1より少し大きい定数を掛けた。

ビームサーチ

上の評価関数を調整すると、局所的には明らかな問題が見つからなくなった。大きな改善があるとしたら「この日は上のほうに収穫機が集まっているけれど、長期的には実は下に集まったほうが得だった」のような状況をできるだけ減らすくらいで、これは適切に状態をまとめてビームサーチすることで実現できそうと思った。

ビームサーチの前提として似た盤面をまとめるために、全体を8×8の4個の領域に区切って、各領域に収穫機が何個あるかで盤面を同一視することにした。ただ、序盤についてはこの同一視はやりすぎで、区切る領域を少し増やしたほうが良いようだった。最終的には時間経過で16個→5個→4個と分割数を減らすように調整した。

終盤のほうが重要なのでビーム幅は終盤に大きいほうがよく、幅30から幅150まで増えていくようにした。

まだ収穫機を買うのをいつ止めるかという問題が残っている。今度は収穫機の調達数で全探索するわけにもいかないので、830日目以降は買わないという単純な仕組みにした。ここは時間があればもう少し詰めたかった。

2021年9月2日木曜日

ARC 126 E - Snack

子供iiが種類jjの菓子をxi,jx_{i, j}個もらうとすると、与えられた問題は以下の条件でxi,j\sum x_{i, j}を最大化する問題と考えられる:

  1. j=1Nxi,jCii[M]\sum_{j=1}^Nx_{i,j} \le C_i \qquad\forall i \in [M]
  2. i=1Mxi,jAjj[N]\sum_{i=1}^Mx_{i, j} \le A_j \qquad \forall j \in [N]
  3. 0xi,jBii[M],j[N]0 \le x_{i, j} \le B_i \qquad \forall i \in [M], \forall j \in [N]
  4. xi,jZi[M],j[N]x_{i, j} \in \mathbb Z \qquad \forall i \in [M], \forall j \in [N]

ただし、[M]={1,2,...,M},[N]={1,2,...,N}[M] = \{1, 2, ..., M\}, [N] = \{1, 2, ..., N\}。実は4の整数制約は外してもよい。つまり、このILPの最適解はLP緩和の最適解にもなっている。以下はConfortiのInteger Programmingのp. 133を基にした説明。


定義: m×nm \times n行列AAの行を2つの集合SSRRに分割する: S˙R=[m]S \dot{\cup} R = [m]SSの行ベクトルの総和 - RRの行ベクトルの総和が0,±10, \pm 1のみからなるベクトルであるとき、S,RS, RAAの公平な行二彩色 (equitable row-bicoloring) と呼ぶ。

定理: 行列AA0,±10, \pm 1のみからなり、各列の非ゼロ成分は高々2個であるとする。AAが公平な行二彩色可能であれば、全ユニモジュラである。

上の制約の1, 2の係数行列について考えると、1の行と2の行に分割すれば公平になっている定理の条件を満たし、全ユニモジュラである。

定理: AAm×nm \times n整数行列とする。AAが全ユニモジュラならば、任意のl,uZn,dZml, u \in \mathbb Z^n, d \in \mathbb Z^mについて凸多面体Q:={x:Axd,lxu}Q := \{x: Ax \le d, l \le x \le u\}は整数多面体である、

この定理より上の制約1~3によって与えられる凸多面体は整数多面体なので、任意の目的関数について(有界なら)最適解の少なくとも一つは整数解である。


従って、ILPに関する双対、つまり元の問題のLP緩和のLP双対に整数制約を課したものを考えると、これについても強双対性が成り立つ。双対問題は以下の条件でi=1MCipi+j=1NAjqj+i=1MBij=1Nri,j\sum_{i=1}^MC_ip_i + \sum_{j=1}^NA_jq_j+\sum_{i=1}^MB_i\sum_{j=1}^Nr_{i, j}を最小化する問題である:

  • pi+qj+ri,j1i[M],j[N]p_i + q_j + r_{i, j} \ge 1 \qquad \forall i \in [M], \forall j \in [N]
  • pi0,qj0,ri,j0i[M],j[N]p_i \ge 0, q_j \ge 0, r_{i, j} \ge 0 \qquad \forall i \in [M], \forall j \in [N]
  • pi,qj,ri,jZi[M],j[N]p_i, q_j, r_{i, j} \in \mathbb Z \qquad \forall i \in [M], \forall j \in [N]

双対問題を、M×NM \times Nのグリッドのいくつかの行と列を選択して覆うようなイメージで解釈した:

  • 行と列の集合S[M],T[N]S \subseteq [M], T \subseteq [N]を任意に選ぶ。言い換えると、pi=1p_i=1とするiiqj=1q_j=1とするjjを選ぶ。
  • iSi \in SについてコストCiC_iを払う。
  • jTj \in TについてコストAjA_jを払う。
  • SSに含まれる行とTTに含まれる列に覆われないすべてのマス(i,j)(i, j)についてコストBiB_iを払う。

最後の「覆われない」の部分の扱いが面倒に見えるので、さらに言い換える:

  • 最初にコストNi=1MBiN\sum_{i=1}^MB_iを払っておく。
  • S[M],T[N]S \subseteq [M], T \subseteq [N]を任意に選ぶ。k=Tk=|T|とする。
  • iSi \in SについてコストCi(Nk)BiC_i-(N-k)B_iを払う。
  • jTj \in TについてコストAji=1MBiA_j-\sum_{i=1}^M B_iを払う。

さて、[N][N]からkk点選ぶと決めたときの最小コストについて考える。S[M],T[N]S \in [M], T \in [N]について(Nk)i=1MBi+iS(Ci(Nk)Bi)+jTAj(N-k)\sum_{i=1}^MB_i + \sum_{i \in S}(C_i-(N-k)B_i)+\sum_{j \in T}A_jが総コストである。TTAjA_jの小さいほうからkk個取ればよく、SSのほうはCi(Nk)Bi<0C_i-(N-k)B_i < 0であるものだけ取ればよい。Ci(Nk)BiC_i-(N-k)B_ikkが減少すると一点で正から負に切り替わる。具体的にはk(NBiCi)/Bik \le \lfloor (NB_i-C_i)/B_i \rfloorで0以下になる。したがって、この閾値を超えたiiについてCiC_iBiB_iの総和を保持することにすればkkごとにO(1){O}(1)で計算できる。(Ai)(A_i)のソートが必要だから全体の計算量はO(NlogN+M){O}(N \log N + M)


LPの整数性について追記した。