[python]伯俊9328:鍵
34016 ワード
質問リンク
https://www.acmicpc.net/problem/9328
問題は特に難しくない.
しかし、考慮すべき例外をよく考えなければならない.
(これは最近の再解答の問題です.既存の解答ではドアや鍵が端にある場合を考慮していないので、再採点結果は間違っています.)
優先度キューを使用して、各文字(.*$aaA)に対して異なる優先度設定を行い、重要な場所で先に探索します.
ドアは開けられるドアと開けられないドアに分けられ、開けられないドアは鍵があるまでドアも訪問しないようにコードが書かれています.
アクセス可能な場所は優先順位キューに配置され、優先順位で先にアクセスします.
例えば、エッジには$、キーx、および空きスペースがあります.つまり、もしあったら、まず$があるところに行って、それから鍵xに行って、それから広いところに行きます.
追加で開けられないドアはキューに入れず、ドアの位置だけを記録します.
上(条件文部分)と下(繰り返し文、ナビゲーション部分)です.
まず、上記のセクションは、現在のアクセス先に対して実行されるアクションです.
p=0は$を表し、私たちが盗むものならansを増やします.
現在位置が空です(.)このドアや開いているドアなら、何もする必要はありません.pass.
△開けられないドアはキューに入れないので、条件はありません.
重要なのは、現在位置に鍵がある場合です.
基本的に鍵が見つかったら、
そして、鍵に合ったドアを訪問したことがある場合は、あなたが探していたすべての「ドア」を開きます.
開いているドアがアクセスできるようになったので、キューに入れます.(開いているドアを持つ優先順位2.)
次の部分は...上下左右に探索するだけです.
さっき開けられなかったドアはまだ訪問していないので、ドアの位置だけを記録します.
https://www.acmicpc.net/problem/9328
に近づく
問題は特に難しくない.
しかし、考慮すべき例外をよく考えなければならない.
(これは最近の再解答の問題です.既存の解答ではドアや鍵が端にある場合を考慮していないので、再採点結果は間違っています.)
に答える
優先度キューを使用して、各文字(.*$aaA)に対して異なる優先度設定を行い、重要な場所で先に探索します.
def priority(c):
if c == "$": # goal
return 0
if "a" <= c <= "z": # key
return 1
if c == ".": # space
return 3
if "A" <= c <= "Z": # door
if c.lower() in keys: # 열 수 있는 문
return 2
else: # 못 여는 문
return 4
注意すべき部分はドアです.ドアは開けられるドアと開けられないドアに分けられ、開けられないドアは鍵があるまでドアも訪問しないようにコードが書かれています.
h, w = map(int, input().split())
board = [list(input()) for _ in range(h)]
keys = set(input())
found_locked_door = {} # 잠겨있는 문이 있는 위치들
for alp in "ABCDEFGHIJKLMNOPQRSTUVWXYZ":
found_locked_door.setdefault(alp, set()) # 특정 알파벳의 문이 둘 이상일수도 있어서 문 위치를 set에 저장
visit = [[0 for _ in range(w)] for _ in range(h)]
pq = PriorityQueue()
以下が主な変数です.keys
はその名の通り鍵のアルファベットを集めることです.found_locked_door
は鍵がかかっているドアの位置を保存しているディックシャーナです.found_locked_door ["A"] = {(1,5), (5,7), (20,5), ...}
は、これまで発見された文Aの位置をこのように保存する.for i in range(h):
for j in range(w):
# 가장자리만 탐색
if (i == 0 or i == h - 1 or j == 0 or j == w - 1) and board[i][j] != "*":
p = priority(board[i][j])
if p == 4: # 못 여는 문
found_locked_door[board[i][j]].add((i, j))
continue
pq.put((p, i, j))
visit[i][j] = 1
「尚根は最初はビルの外にいて、ビルの縁の壁を通ってビルの内外に出入りすることができた」.したがって,最初はエッジのみをチェックする.アクセス可能な場所は優先順位キューに配置され、優先順位で先にアクセスします.
例えば、エッジには$、キーx、および空きスペースがあります.つまり、もしあったら、まず$があるところに行って、それから鍵xに行って、それから広いところに行きます.
追加で開けられないドアはキューに入れず、ドアの位置だけを記録します.
while not pq.empty():
p, y, x = pq.get()
if p == 0: # goal
ans += 1
elif p == 1: # key
keys.add(board[y][x])
if board[y][x].upper() in found_locked_door: # 해당 열쇠에 맞는 문 찾았었음, 열어버리자!
for door_y, door_x in found_locked_door[board[y][x].upper()]:
# 해당 열쇠에 맞는, 이미 찾았었던, 모든 문에 대해
visit[door_y][door_x] = 1
pq.put((2, door_y, door_x))
elif p == 2 or p == 3:
pass
for i in range(4):
ny, nx = y + dy[i], x + dx[i]
if in_range(ny, nx) and not visit[ny][nx] and board[ny][nx] != "*":
np = priority(board[ny][nx])
if np == 4: # 못 여는 문
found_locked_door[board[ny][nx]].add((ny, nx))
continue
visit[ny][nx] = 1
pq.put((np, ny, nx))
最後にメインアルゴリズムです.上(条件文部分)と下(繰り返し文、ナビゲーション部分)です.
まず、上記のセクションは、現在のアクセス先に対して実行されるアクションです.
p=0は$を表し、私たちが盗むものならansを増やします.
現在位置が空です(.)このドアや開いているドアなら、何もする必要はありません.pass.
△開けられないドアはキューに入れないので、条件はありません.
重要なのは、現在位置に鍵がある場合です.
基本的に鍵が見つかったら、
keys
に追加します.そして、鍵に合ったドアを訪問したことがある場合は、あなたが探していたすべての「ドア」を開きます.
開いているドアがアクセスできるようになったので、キューに入れます.(開いているドアを持つ優先順位2.)
次の部分は...上下左右に探索するだけです.
さっき開けられなかったドアはまだ訪問していないので、ドアの位置だけを記録します.
正しいコード
import sys
from queue import PriorityQueue
# sys.setrecursionlimit(10 ** 8) # pypy 제출시 삭제!
input = lambda: sys.stdin.readline().rstrip()
in_range = lambda y, x: 0 <= y < h and 0 <= x < w
dy = [1, 0, -1, 0]
dx = [0, 1, 0, -1]
def priority(c):
if c == "$": # goal
return 0
if "a" <= c <= "z": # key
return 1
if c == ".": # space
return 3
if "A" <= c <= "Z": # door
if c.lower() in keys: # 열 수 있는 문
return 2
else: # 못 여는 문
return 4
for _ in range(int(input())):
h, w = map(int, input().split())
board = [list(input()) for _ in range(h)]
keys = set(input())
found_locked_door = {} # 잠겨있는 문이 있는 위치들
for alp in "ABCDEFGHIJKLMNOPQRSTUVWXYZ":
found_locked_door.setdefault(alp, set()) # 특정 알파벳의 문이 둘 이상일수도 있어서 문 위치를 set에 저장
visit = [[0 for _ in range(w)] for _ in range(h)]
pq = PriorityQueue()
ans = 0
for i in range(h):
for j in range(w):
# 가장자리만 탐색
if (i == 0 or i == h - 1 or j == 0 or j == w - 1) and board[i][j] != "*":
p = priority(board[i][j])
if p == 4: # 못 여는 문
found_locked_door[board[i][j]].add((i, j))
continue
pq.put((p, i, j))
visit[i][j] = 1
while not pq.empty():
p, y, x = pq.get()
if p == 0: # goal
ans += 1
elif p == 1: # key
keys.add(board[y][x])
if board[y][x].upper() in found_locked_door: # 해당 열쇠에 맞는 문 찾았었음, 열어버리자!
for door_y, door_x in found_locked_door[board[y][x].upper()]:
# 해당 열쇠에 맞는, 이미 찾았었던, 모든 문에 대해
visit[door_y][door_x] = 1
pq.put((2, door_y, door_x))
elif p == 2 or p == 3:
pass
for i in range(4):
ny, nx = y + dy[i], x + dx[i]
if in_range(ny, nx) and not visit[ny][nx] and board[ny][nx] != "*":
np = priority(board[ny][nx])
if np == 4: # 못 여는 문
found_locked_door[board[ny][nx]].add((ny, nx))
continue
visit[ny][nx] = 1
pq.put((np, ny, nx))
print(ans)
Reference
この問題について([python]伯俊9328:鍵), 我々は、より多くの情報をここで見つけました https://velog.io/@sunkyuj/python-백준-9328-열쇠テキストは自由に共有またはコピーできます。ただし、このドキュメントのURLは参考URLとして残しておいてください。
Collection and Share based on the CC Protocol