目次

AtCoder Beginner Contest 347 F,G問題メモ

AtCoder Beginner Contest 347

F - Non-overlapping Squares

F - Non-overlapping Squares

問題

解法

正方形を選ぶ個数が3つというのが重要で、必ずグリッド全体を、正方形を切らずに「1:2」で分けられる直線が存在する。

□□□□□□□
□□□●●□□
□☆☆●●□□
□☆☆□□□□__↙この線で分割できる
□□▲▲□□□
□□▲▲□□□
□□□□□□□

(4つ以上だと無理な配置が存在する)

□□□□□□□
□□□●●□□  どの直線で切ってもどれかの正方形が分割される
□☆☆●●□□
□☆☆□◎◎□
□□▲▲◎◎□
□□▲▲□□□
□□□□□□□

2個の方はさらに1個ずつに分けられるので、グリッドを「それぞれ1個ずつ正方形を内包する」という3つの領域に分けられる。

縦または横に3つに切る型
①❷③  ①①①
①❷③  ❷❷❷      ※❷だけ黒いのは、単に視認性のため
①❷③  ③③③

T字型
①①①  ①❷❷  ①①❷  ①①③
❷❷③  ①③③  ①①❷  ❷❷③
❷❷③  ①③③  ③③③  ❷❷③

この分け方・分ける位置を全探索する。分ける位置を決めたときの答えを効率的に求められるよう、前計算する。

その後、❷に含まれる正方形の位置を全探索する。

1つ決め打つと、どの分け方のパターンをとっても、その正方形と被らない最大の①、③の領域が決まり、 その領域内に内包される正方形の最大スコアは、(b) を参照するとすぐに調べることができる。

(a)、(b)の前計算と、❷の位置の全探索、いずれも $O(N^2)$ でできる。

Python3

G - Grid Coloring 2

G - Grid Coloring 2

問題

解法

グラフを上手く作って、最小カット問題に落とし込む。

コストが2乗であり、「離れれば離れるほどコストの増え方が増加する」ような形をしているため、上手くコストを設定できる。1)
仮に、「1離れてればコスト1、2離れてたら5、3離れてたら8」のように、 コストの増分が 1→5で4、5→8で3 と減っている箇所があるような形だったらダメ。

最小カットで解けるようにグラフを作り、コストを設定する。

1つのマスにつき、以下のような4頂点を割り当て、s-t で結んだものを考える。
頂点“(2以上)“は、S に属するとき、そのマスの数字が2以上であることを示す。T に属すると2未満となる。

マスa   ,---> (2以上) ---> (3以上) ---> (4以上) ---> (5以上) ---,
マスb  s ---> (2以上) ---> (3以上) ---> (4以上) ---> (5以上) ----> t
マスc   `---> (2以上) ---> (3以上) ---> (4以上) ---> (5以上) ---'
  :

このようなグラフ上で辺のコストを考える。

1つのマスの中の制約に関するコスト

矛盾を防ぐ

あるマスの数字が3以上かつ2未満であることは当然だがあり得ない。
つまり、(3以上)がS、(2以上)がTであることは許されない。
そのようなグループ分けが発生しないよう、戻るINF辺を張る。

s      (2以上) <-INF- (3以上) <-INF- (4以上) <-INF (5以上)      t
初期値

既に0以外の値が埋められたマスは、そのマス以外の数字を選べないよう、INF辺を設定する。

はじめから 3 が埋められたマス

s -INF-> (2以上) -INF-> (3以上)      (4以上) -INF-> (5以上) -INF-> t

0であるマスは、どの数字を選ぼうとも「そのマス単体だけの」コストは発生しないので、辺コストは全て0である。
(したがって、実際には辺を張る必要は無い)

s --0--> (2以上) --0--> (3以上) --0--> (4以上) --0--> (5以上) --0--> t

2つのマスの関係性に関するコスト

まず、マスaが3、マスbが4の場合を考えてみる。グリッドのコストへの寄与は1である。

                 S            S            T            T
マスa   ,---> (2以上) ---> (3以上) ---> (4以上) ---> (5以上) ---,
       s                                  ↑1                    -> t
マスb   `---> (2以上) ---> (3以上) ---> (4以上) ---> (5以上) ---'
                 S            S            S            T

(4以上)の間に1の辺を張れば、実現できる。
他の(2以上)、(3以上)、(5以上) の間にも同様のことが言えるので、それぞれにコスト1の辺が張られる。

マスaが2、マスbが4の場合を考えてみる。グリッドのコストへの寄与は4である。

                 S            T            T            T
マスa   ,---> (2以上) ---> (3以上) ---> (4以上) ---> (5以上) ---,
       s                     ↑1   ↖2    ↑1                    -> t
マスb   `---> (2以上) ---> (3以上) ---> (4以上) ---> (5以上) ---'
                 S            S            S            T

このとき、既に(3以上)と(4以上)の間にそれぞれコスト1が張られているので、追加で必要なコスト2の辺を、ナナメに張ればよい。

さらにマスaが1、マスbが4の場合を考えてみる。グリッドのコストへの寄与は9である。

                 T            T            T            T
マスa   ,---> (2以上) ---> (3以上) ---> (4以上) ---> (5以上) ---,
       s        ↑1   ↖2    ↑1   ↖2    ↑1                    -> t
マスb   `---> (2以上) ---> (3以上) ---> (4以上) ---> (5以上) ---'
                 S            S            S            T

既に1,2,1,2,1のコストの辺が張られているので、追加で必要なのは2である。bの(4以上)→aの(2以上) に、コスト2の辺を張る。

このように、異なる頂点間で

の辺を張れば、「差の2乗」を表現できる。

この過程で、どの辺コストも負にならないために必要なのが、 最初の「離れれば離れるほどコストの増え方が増加する」性質となる。

復元

コストを求めるだけなら簡単だが、今回はその盤面を構築しなければならない。

最小カットを流すと、「どの辺がカットされたか」は、再度始点から調べることで列挙できる。

例えば、マスaの(4以上) → マスbの(3以上) の辺がカットの1つにあった場合、

このように、最大・最小の両側から範囲が限定される。
マスによっては、最大方向・最小方向の片方からしか限定されないものもあるが、その場合は限定された方を採用する。

これで調べていけるのだが、あくまでカット辺は「コストが発生する」辺なので、

3 3 3 3
3 0 0 3
3 3 3 3

の'0'のように、コストが最大4方向のいずれでも発生させないことができるマスは、カット辺に関与せず、範囲が限定されないままとなる。

ただ、このような頂点は四方を同じ数字で囲まれているはずなので、後からDFSなり何なりすれば補間出来る。

Python3

1)
Monge性という