服を着たゾウに花束を

勉強の記録とか。

AtCoder Beginner Contest 176 振り返り

D - Wizard in Maze

 

魔術師が迷路にいる.

上下左右に移動する,あるいはコスト1で自分を中心とした5×5のマスのどれかにワープすることができる.

なるべく少ないワープ回数で移動したい.

 

解)

ワープ回数0のエリア,1のエリア,…と分けていき,ゴールまでたどり着けばよい.

 

具体的な実装は以下のコードのものを参考にした.

Submission #16141246 - AtCoder Beginner Contest 176

 

ワープ回数をdist,現在位置をdeqとする.これらは一次元配列にして計算速度を早くする.

 

初期設定:

def main(wallSxSyTxTy):
    INF = 1 << 30
    H, W = wall.shape
    S = Sx * W + Sy
    T = Tx * W + Ty
    dist = np.full(H * W, INF, np.int64)
    deq = np.empty(H * W + 100, np.int64)
    dist[S] = 0
    deq[0], l, r = S, 01

 

 

実際に移動するところは以下のように実装する.

 

 
    while l < r:
        v, l = deq[l], l + 1
        vx, vy = divmod(v, W)
        # そのままあるく
        for dx, dy in *1:
            wx, wy = vx + dx, vy + dy
            if not (0 <= wx < H):
                continue
            if not (0 <= wy < W):
                continue
            if wall[wx, wy]:
                continue
            w = wx * W + wy
            if dist[w] <= dist[v]:
                continue
            dist[w] = dist[v]
            deq[l - 1], l = w, l - 1
        # ワープする
        for dx in range(-23):
            for dy in range(-23):
                wx, wy = vx + dx, vy + dy
                if not (0 <= wx < H):
                    continue
                if not (0 <= wy < W):
                    continue
                if wall[wx, wy]:
                    continue
                w = wx * W + wy
                if dist[w] <= dist[v] + 1:
                    continue
                dist[w] = dist[v] + 1
                deq[r], r = w, r + 1
    ans = dist[T]
    if ans == INF:
        ans = -1
    return ans

 

numbaを利用すると時間内に通る.

numbaをインポートし,関数の頭に@njitをつけることで使用できる.

import numba
from numba import njit, b1, i4, i8, f8

 

@njit*2
HW = list(zip(*[iter(HW)] * 2))

 

最大値を取り得るマスの数を数え,そのすべてのマスに箱がおかれているかチェックする.

    cnt = A.count(a) * B.count(b) - len([0 for h, w in HW if A[h] == a and B[w] == b])

 

置かれていたら縦と横の和から1を引き,それ以外はそのまま和を出力すればよい.

    print(a + b - (cnt == 0))

 

Submission #16187005 - AtCoder Beginner Contest 176

 

 

 

 

 

*1:10), (01), (-10), (0, -1

*2:b1[:, :], i8, i8, i8, i8), cache=True)

def main(wallSxSyTxTy):

 

参考:

qiita.com

 

E - Bomber

ボンバーマン

十字に爆発する爆弾を仕掛け,なるべく多くの箱を壊したい.

縦と横の箱の個数を数えればよいが,箱のあるマスに仕掛けることもでき,ここに爆弾を置くかどうかで場合分け.

フィールドは最大で3*10^5 四方,,箱の数も最大3*10^5 個.

 

解)

箱があるマスはzip関数で記録しておくと良い.

H, W, M, *HW = map(intopen(0).read().split(