Problem:


会津の埋蔵金

 会津には古くから伝わる埋蔵金の伝説があります。あなたは、遂に埋蔵金が埋まっている場所を突き止めました。埋蔵金が埋まっている深さ、掘り進める地層の状態が分かっているので、綿密に計画を立てれば最小費用で埋蔵金まで到達することができます。そこであなたは、地層の状態を読み取って埋蔵金の埋まっている深さまで最小費用で到達するルートを算出するプログラムを作成することにしました。

地層の状態は 2 次元格子状に配置されたセルで表わされ、各セルの位置は座標 (x,y) で表されます。左上を (1,1) とし、x 座標は右に行くにつれて大きくなり、y 座標は下に深くなるにつれて大きくなるものとします。あなたは y 座標の一番小さいセルのうち一つを選んでそこから掘り始め、y 座標の一番大きいセルの一つまで掘り進めます。地層には以下の 2 種類のセルがあります：

    
土の詰まったセル。掘るのに、セルごとに決められた費用がかかる。

     
酸素のたまったセル。掘る必要はなく、セルごとに決まった量の酸素を補給できる。一度酸素を補給したセルの酸素はなくなり、再度の補給はできない。また、このセルに辿りついたら必ず酸素の補給をしなければならない。

     

 

あるセルから掘ることができるのは左右と下方向のセルのみです。
一度掘ったセルを左右に移動することはできますが、上に移動することはできません。

発掘にあたっては、酸素ボンベを携帯しなければなりません。酸素ボンベの残量が 0 になった瞬間、移動も発掘も酸素の補給もできなくなります。残量はセルを移動するたびに 1 減ります。酸素ボンベの残量が 0 で埋蔵金の埋まっている深さまで到達しても、到達したとみなされません。また、酸素のたまったセルでは酸素を補給することができますが、容量を超えた分は廃棄されます。

 地層のサイズ 、発掘費用、酸素ボンベの容量、初期状態で持っている酸素の量、地層の情報を入力とし、一番深いセルまでたどりつくための最小費用を出力するプログラムを作成してください。ただし、最小費用が発掘費用を超えてしまう場合や、どのように掘り進めても埋蔵金にたどりつけない場合は“NA”と出力してください。

Input

複数のデータセットの並びが入力として与えられる。入力の終わりはゼロふたつの行で示される。
各データセットは以下の形式で与えられる。

W H
f m o
c1,1 c2,1 ... cW,1
c1,2 c2,2 ... cW,2
...
c1,H c2,H ... cW,H

１行目に地層の横方向のサイズ W, 縦方向のサイズ H (3 ≤ W, H ≤ 10) が与えられる。 ２行目にあなたの発掘費用を表す整数 f (1 ≤ f ≤ 10000)、酸素ボンベの容量を表す整数 m (3 ≤ m ≤ 50)、初期状態で持っている酸素の量を表す整数 o (o ≤ m) が与えられる。

続く H 行に地層の情報 ci,j が与えられる。ci,j は、座標 (i, j) に対するセルの情報を表し、以下の形式で与えられる：

          負の値の場合、土の詰まったセルで、値は費用を表す

          正の値の場合、酸素のたまったセルで、値は酸素の量を表す

ただし、酸素のたまったセルは 50 箇所以内である。

データセットの数は50 を超えない。

Output

データセットごとに、最少費用または NA を1行に出力する。

Sample Input

3 3
100 10 10
-100 -20 -100
-100 -20 -100
-100 -20 -100
3 3
100 10 10
-100 -20 -100
-100 -20 -20
-100 -60 -20
3 3
100 10 3
-100 -20 -100
-20 -20 -20
-20 -100 -20
3 3
100 3 3
-100 -20 -30
-100 -20 2
-100 -20 -20
4 5
1500 5 4
-10 -380 -250 -250
-90 2 -80 8
-250 -130 -330 -120
-120 -40 -50 -20
-250 -10 -20 -150
0 0

Output for the Sample Input

60
80
NA
50
390



Sample input:
3 3
100 10 10
-100 -20 -100
-100 -20 -100
-100 -20 -100
3 3
100 10 10
-100 -20 -100
-100 -20 -20
-100 -60 -20
3 3
100 10 3
-100 -20 -100
-20 -20 -20
-20 -100 -20
3 3
100 3 3
-100 -20 -30
-100 -20 2
-100 -20 -20
4 5
1500 5 4
-10 -380 -250 -250
-90 2 -80 8
-250 -130 -330 -120
-120 -40 -50 -20
-250 -10 -20 -150
0 0


Sample output:
60
80
NA
50
390

Submission status: Time Limit Exceeded

Solution code:
from collections import deque
from copy import deepcopy

def bfs(inicost, inioxy, inif, m, inio, H):
    q = deque()
    anss = []

    for i in range(W):
        cost = deepcopy(inicost)
        oxy = deepcopy(inioxy)
        nf = inif + cost[0][i]
        no = min(inio - 1 + oxy[0][i], m)
        if nf > 0 and no > 0:
            cost[0][i] = 0
            oxy[0][i] = 0
            q.append([0, i, nf, no, cost, oxy, {(0, i): (nf, no)}])

    while q:
        y, x, f, o, cost, oxy, d = q.popleft()
        if y == H - 1:
            anss.append(inif - f)
            continue

        for dy, dx in [(0, -1), (0, 1), (1, 0)]:
            ny = y + dy
            nx = x + dx
            ncost = deepcopy(cost)
            noxy = deepcopy(oxy)
            nd = deepcopy(d)
            if ny in range(H) and nx in range(W):
                nf = f + ncost[ny][nx]
                no = min(o - 1 + noxy[ny][nx], m)
                if nf > 0 and no > 0 and ((ny, nx) not in nd or nf > nd[ny, nx][0] or no > nd[ny, nx][1]):
                    ncost[ny][nx] = 0
                    noxy[ny][nx] = 0
                    nd[ny, nx] = (nf, no)
                    q.append([ny, nx, nf, no, ncost, noxy, nd])

    if len(anss) == 0:
        return 'NA'
    else:
        return min(anss)

if __name__ == '__main__':
    while True:
        W, H = map(int, input().split())
        if W == 0:
            break
        f, m, o = map(int, input().split())
        cost = []
        for _ in range(H):
            l = list(map(int, input().split()))
            cost.append(l)
        oxy = deepcopy(cost)

        for i in range(H):
            for j in range(W):
                if cost[i][j] > 0:
                    cost[i][j] = 0
                else:
                    oxy[i][j] = 0

        print(bfs(cost, oxy, f, m, o, H))

Submission status: Accepted

Solution code:
import sys
sys.setrecursionlimit(1000000)
INF = 10 ** 20

def update_state(state, newx):
  tmp = list(state)
  tmp[newx] = 1
  return tuple(tmp)

def get_co(x, y):
  dc = do = 0
  score = mp[y][x]
  if score < 0:
    dc = -score
  else:
    do = score
  return dc, do

def minimum_cost(x, y, state, ox, goal, dic, w, m):
  if (x, y, state, ox) in dic:
    return dic[(x, y, state, ox)]
  if y == goal:
    return 0
  if ox <= 1:
    return INF
  
  ret = INF
  
  if x >= 1:
    if state[x - 1] == 0:
      dc, do = get_co(x - 1, y)
      ret = min(ret, minimum_cost(x - 1, y, update_state(state, x - 1), min(ox + do - 1, m), goal, dic, w, m) + dc)
    else:
      ret = min(ret, minimum_cost(x - 1, y, state, ox - 1, goal, dic, w, m))
  
  if x < w - 1:
    if state[x + 1] == 0:
      dc, do = get_co(x + 1, y)
      ret = min(ret, minimum_cost(x + 1, y, update_state(state, x + 1), min(ox + do - 1, m), goal, dic, w, m) + dc)
    else:
      ret = min(ret, minimum_cost(x + 1, y, state, ox - 1, goal, dic, w, m))
 
 
  dc, do = get_co(x, y + 1)
  ret = min(ret, minimum_cost(x, y + 1, tuple((1 if i == x else 0 for i in range(w))), min(ox + do - 1, m), goal, dic, w, m) + dc)
  dic[(x, y, state, ox)] = ret
  return ret

while True:
  w, h = map(int, input().split())
  if w == 0:
    break
  f, m, o = map(int, input().split())
  mp = [list(map(int, input().split())) for _ in range(h)]
  if o <= 1:
    print("NA")
    continue
  dic = {}
  ans = INF
  for i in range(w):
    dc, do = get_co(i, 0)
    state = tuple(1 if i == j else 0 for j in range(w))
    ans = min(ans, minimum_cost(i, 0, state, min(o + do - 1, m), h - 1, dic, w, m) + dc)
  if ans > f:
    print("NA")
  else:
    print(ans)

Submission status: Accepted

Solution code:
INF = 10 ** 20

def update_state(state, newx):
  tmp = list(state)
  tmp[newx] = 1
  return tuple(tmp)

def get_co(x, y):
  dc = do = 0
  score = mp[y][x]
  if score < 0:
    dc = -score
  else:
    do = score
  return dc, do

def minimum_cost(x, y, state, ox, goal, dic, w, m):
  if (x, y, state, ox) in dic:
    return dic[(x, y, state, ox)]
  if y == goal:
    return 0
  if ox <= 1:
    return INF
  
  ret = INF
  
  if x >= 1:
    if state[x - 1] == 0:
      dc, do = get_co(x - 1, y)
      ret = min(ret, minimum_cost(x - 1, y, update_state(state, x - 1), min(ox + do - 1, m), goal, dic, w, m) + dc)
    else:
      ret = min(ret, minimum_cost(x - 1, y, state, ox - 1, goal, dic, w, m))
  
  if x < w - 1:
    if state[x + 1] == 0:
      dc, do = get_co(x + 1, y)
      ret = min(ret, minimum_cost(x + 1, y, update_state(state, x + 1), min(ox + do - 1, m), goal, dic, w, m) + dc)
    else:
      ret = min(ret, minimum_cost(x + 1, y, state, ox - 1, goal, dic, w, m))
 
 
  dc, do = get_co(x, y + 1)
  ret = min(ret, minimum_cost(x, y + 1, tuple((1 if i == x else 0 for i in range(w))), min(ox + do - 1, m), goal, dic, w, m) + dc)
  dic[(x, y, state, ox)] = ret
  return ret

while True:
  w, h = map(int, input().split())
  if w == 0:
    break
  f, m, o = map(int, input().split())
  mp = [list(map(int, input().split())) for _ in range(h)]
  if o <= 1:
    print("NA")
    continue
  dic = {}
  ans = INF
  for i in range(w):
    dc, do = get_co(i, 0)
    state = tuple(1 if i == j else 0 for j in range(w))
    ans = min(ans, minimum_cost(i, 0, state, min(o + do - 1, m), h - 1, dic, w, m) + dc)
  if ans > f:
    print("NA")
  else:
    print(ans)

Submission status: Accepted

Solution code:
import queue

di = [0, 1, 0, -1]
dj = [1, 0, -1, 0]

while True:
    w,h = map(int,input().split())
    if w == 0:
        break
    f, m, o = map(int,input().split())
    c = [list(map(int,input().split())) for _ in range(h)]
    d = [[[1e9]*w for x in range(h)] for y in range(m+1)]

    que = queue.PriorityQueue()
    for j in range(w):
        d[o-1][0][j] = -min(0,c[0][j])
        que.put((-min(0,c[0][j]),o-1,0,j))

    while not que.empty():
        p = que.get()
        ox = p[1]
        i = p[2]
        j = p[3]
        if d[ox][i][j] < p[0] or ox <= 1:
            continue
        for k in range(4):
            ni = i+di[k]
            nj = j+dj[k]
            if ni<0 or ni>=h or nj<0 or nj>=w:
                continue
            if c[ni][nj] < 0:
                if d[ox-1][ni][nj] > d[ox][i][j] - c[ni][nj]:
                    d[ox-1][ni][nj] = d[ox][i][j] - c[ni][nj]
                    que.put((d[ox-1][ni][nj],ox-1,ni,nj))
            else:
                nox = min(ox-1+c[ni][nj],m)
                if d[nox][ni][nj] > d[ox][i][j]:
                    d[nox][ni][nj] = d[ox][i][j]+0
                    que.put((d[nox][ni][nj],nox,ni,nj))
    ans = 1e9
    for j in range(w):
        for ox in range(1,m+1):
            ans = min(ans, d[ox][h-1][j])
    if ans <= f:
        print(ans)
    else:
        print('NA')

Submission status: Runtime Error

Solution code:
INF = 10 ** 20

def update_state(state, newx):
  tmp = list(state)
  tmp[newx] = 1
  return tuple(tmp)

def get_co(x, y):
  dc = do = 0
  score = mp[y][x]
  if score < 0:
    dc = -score
  else:
    do = score
  return dc, do

def minimum_cost(nowx, nowy, state, ox, goal, dic, w, m):
  if (nowx, nowy, state, ox) in dic:
    return dic[(nowx, nowy, state, ox)]
  if nowy == goal:
    return 0
  if ox <= 1:
    return INF
  
  ret = INF
  
  left = right = None
  for i in range(nowx + 1, w):
    if state[i] == 0:
      right = i
      break

  for i in range(nowx - 1, -1, -1):
    if state[i] == 0:
      left = i
      break

  if left != None:
    dc, do = get_co(left, nowy)
    ret = min(ret, minimum_cost(left, nowy, update_state(state, left), min(ox + do - 1, m), goal, dic, w, m) + dc)
    for i in range(left + 1, nowx):
      ret = min(ret, minimum_cost(i, nowy, state, ox - 1, goal, dic, w, m))
  
  if right != None:
    dc, do = get_co(right, nowy)
    ret = min(ret, minimum_cost(right, nowy, update_state(state, right), min(ox + do - 1, m), goal, dic, w, m) + dc)
    for i in range(nowx + 1, right):
      ret = min(ret, minimum_cost(i, nowy, state, ox - 1, goal, dic, w, m))
  
  dc, do = get_co(nowx, nowy + 1)
  ret = min(ret, minimum_cost(nowx, nowy + 1, tuple((1 if i == nowx else 0 for i in range(w))), min(ox + do - 1, m), goal, dic, w, m) + dc)
  dic[(nowx, nowy, state, ox)] = ret
  return ret

while True:
  w, h = map(int, input().split())
  if w == 0:
    break
  f, m, o = map(int, input().split())
  if o <= 1:
    print("NA")
    continue
  mp = [list(map(int, input().split())) for _ in range(h)]
  dic = {}
  ans = INF
  for i in range(w):
    dc, do = get_co(i, 0)
    ans = min(ans, minimum_cost(i, 0, tuple(1 if i == j else 0 for j in range(w)), min(o + do - 1, m), h - 1, dic, w, m) + dc)
  if ans > f:
    print("NA")
  else:
    print(ans)

Submission status: Runtime Error

Solution code:
import sys
sys.setrecursionlimit(1000000)
INF = 10 ** 20

def update_state(state, newx):
  tmp = list(state)
  tmp[newx] = 1
  return tuple(tmp)

def get_co(x, y):
  dc = do = 0
  score = mp[y][x]
  if score < 0:
    dc = -score
  else:
    do = score
  return dc, do

def minimum_cost(nowx, nowy, state, ox, goal, dic, w, m):
  if (nowx, nowy, state, ox) in dic:
    return dic[(nowx, nowy, state, ox)]
  if nowy == goal:
    return 0
  if ox <= 1:
    return INF
  
  ret = INF
  
  left = right = None
  for i in range(nowx + 1, w):
    if state[i] == 0:
      right = i
      break

  for i in range(nowx - 1, -1, -1):
    if state[i] == 0:
      left = i
      break

  if left != None:
    dc, do = get_co(left, nowy)
    ret = min(ret, minimum_cost(left, nowy, update_state(state, left), min(ox + do - 1, m), goal, dic, w, m) + dc)
    for i in range(left + 1, nowx):
      ret = min(ret, minimum_cost(i, nowy, state, ox - 1, goal, dic, w, m))
  
  if right != None:
    dc, do = get_co(right, nowy)
    ret = min(ret, minimum_cost(right, nowy, update_state(state, right), min(ox + do - 1, m), goal, dic, w, m) + dc)
    for i in range(nowx + 1, right):
      ret = min(ret, minimum_cost(i, nowy, state, ox - 1, goal, dic, w, m))
  
  dc, do = get_co(nowx, nowy + 1)
  ret = min(ret, minimum_cost(nowx, nowy + 1, tuple((1 if i == nowx else 0 for i in range(w))), min(ox + do - 1, m), goal, dic, w, m) + dc)
  dic[(nowx, nowy, state, ox)] = ret
  return ret

while True:
  w, h = map(int, input().split())
  if w == 0:
    break
  f, m, o = map(int, input().split())
  if o <= 1:
    print("NA")
    continue
  mp = [list(map(int, input().split())) for _ in range(h)]
  dic = {}
  ans = INF
  for i in range(w):
    dc, do = get_co(i, 0)
    ans = min(ans, minimum_cost(i, 0, tuple(1 if i == j else 0 for j in range(w)), min(o + do - 1, m), h - 1, dic, w, m) + dc)
  if ans > f:
    print("NA")
  else:
    print(ans)

Submission status: Runtime Error

Solution code:
import sys
sys.setrecursionlimit(1000000)
INF = 10 ** 20

def update_state(state, newx):
  tmp = list(state)
  tmp[newx] = 1
  return tuple(tmp)

def get_co(x, y):
  dc = do = 0
  score = mp[y][x]
  if score < 0:
    dc = -score
  else:
    do = score
  return dc, do

def minimum_cost(x, y, state, ox, goal, dic, w, m):
  if (x, y, state, ox) in dic:
    return dic[(x, y, state, ox)]
  if y == goal:
    return 0
  if ox <= 1:
    return INF
  
  ret = INF
  
  left = right = None
  for i in range(x + 1, w):
    if state[i] == 0:
      right = i
      break

  for i in range(x - 1, -1, -1):
    if state[i] == 0:
      left = i
      break

  if left != None:
    dc, do = get_co(left, y)
    ret = min(ret, minimum_cost(left, y, update_state(state, left), min(ox + do - 1, m), goal, dic, w, m) + dc)
    for i in range(left + 1, x):
      ret = min(ret, minimum_cost(i, y, state, ox - (x - i), goal, dic, w, m))
  
  if right != None:
    dc, do = get_co(right, y)
    ret = min(ret, minimum_cost(right, y, update_state(state, right), min(ox + do - 1, m), goal, dic, w, m) + dc)
    for i in range(x + 1, right):
      ret = min(ret, minimum_cost(i, y, state, ox - (i - x), goal, dic, w, m))
  
  dc, do = get_co(x, y + 1)
  ret = min(ret, minimum_cost(x, y + 1, tuple((1 if i == x else 0 for i in range(w))), min(ox + do - 1, m), goal, dic, w, m) + dc)
  dic[(x, y, state, ox)] = ret
  return ret

while True:
  w, h = map(int, input().split())
  if w == 0:
    break
  f, m, o = map(int, input().split())
  if o <= 1:
    print("NA")
    continue
  mp = [list(map(int, input().split())) for _ in range(h)]
  dic = {}
  ans = INF
  for i in range(w):
    dc, do = get_co(i, 0)
    state = tuple(1 if i == j else 0 for j in range(w))
    ans = min(ans, minimum_cost(i, 0, state, min(o + do - 1, m), h - 1, dic, w, m) + dc)
  if ans > f:
    print("NA")
  else:
    print(ans)

Submission status: Runtime Error

Solution code:
import sys
sys.setrecursionlimit(1000000)
INF = 10 ** 20

def update_state(state, newx):
  tmp = list(state)
  tmp[newx] = 1
  return tuple(tmp)

def get_co(x, y):
  dc = do = 0
  score = mp[y][x]
  if score < 0:
    dc = -score
  else:
    do = score
  return dc, do

def minimum_cost(x, y, state, ox, goal, dic, w, m):
  if (x, y, state, ox) in dic:
    return dic[(x, y, state, ox)]
  if y == goal:
    return 0
  if ox <= 1:
    return INF
  
  ret = INF
  
  if x >= 1:
    if state[x - 1] == 0:
      dc, do = get_co(x - 1, y)
      ret = min(ret, minimum_cost(x - 1, y, update_state(state, x - 1), min(ox + do - 1, m), goal, dic, w, m) + dc)
    else:
      ret = min(ret, minimum_cost(x - 1, y, state, ox - 1, goal, dic, w, m))
  
  if x < w - 1:
    if state[x + 1] == 0:
      dc, do = get_co(x + 1, y)
      ret = min(ret, minimum_cost(x + 1, y, update_state(state, x + 1), min(ox + do - 1, m), goal, dic, w, m) + dc)
    else:
      ret = min(ret, minimum_cost(x + 1, y, state, ox - 1, goal, dic, w, m))
 
  """
  left = right = None
  for i in range(x + 1, w):
    if state[i] == 0:
      right = i
      break

  for i in range(x - 1, -1, -1):
    if state[i] == 0:
      left = i
      break

  if left != None:
    dc, do = get_co(left, y)
    ret = min(ret, minimum_cost(left, y, update_state(state, left), min(ox + do - 1, m), goal, dic, w, m) + dc)
    for i in range(left + 1, x):
      ret = min(ret, minimum_cost(i, y, state, ox - (x - i), goal, dic, w, m))
  
  if right != None:
    dc, do = get_co(right, y)
    ret = min(ret, minimum_cost(right, y, update_state(state, right), min(ox + do - 1, m), goal, dic, w, m) + dc)
    for i in range(x + 1, right):
      ret = min(ret, minimum_cost(i, y, state, ox - (i - x), goal, dic, w, m))
  """  
  dc, do = get_co(x, y + 1)
  ret = min(ret, minimum_cost(x, y + 1, tuple((1 if i == x else 0 for i in range(w))), min(ox + do - 1, m), goal, dic, w, m) + dc)
  dic[(x, y, state, ox)] = ret
  return ret

while True:
  w, h = map(int, input().split())
  if w == 0:
    break
  f, m, o = map(int, input().split())
  if o <= 1:
    print("NA")
    continue
  mp = [list(map(int, input().split())) for _ in range(h)]
  dic = {}
  ans = INF
  for i in range(w):
    dc, do = get_co(i, 0)
    state = tuple(1 if i == j else 0 for j in range(w))
    ans = min(ans, minimum_cost(i, 0, state, min(o + do - 1, m), h - 1, dic, w, m) + dc)
  if ans > f:
    print("NA")
  else:
    print(ans)