[Algorithm] BaekJoon : 19238. タクシー台
[問題のショートカット]https://www.acmicpc.net/problem/19238
StartLinkは「StartTaxi」というタクシー事業を開始した.タクシーを起動するのは特別で、お客さんを目的地に送るたびに燃料が充電され、燃料が切れた当日の仕事は終わります.
タクシー運転手の崔伯俊さんは今日、M人の乗客を乗せることを目標にしています.白俊が活動する分野はNだ.×Nサイズのメッシュで表すことができ、各セルが空または壁になっています.タクシーが空席の場合、上下左右に隣接する空席の一つに移動できます.アルゴリズム経験豊富なBaek Junは,特定の位置に移動すると常に最短経路に移動する.
M人の乗客は1つのスペースに立って、別のスペースの1つに移動する準備をしています.複数の乗客が一緒に搭乗する場合はありません.そのため、白俊は乗客1人を乗せて目的地に向かうM回を繰り返した.乗客一人一人が動かず、出発地でタクシーに乗るしかなく、目的地の地下タクシーに乗るしかありません.
白俊が乗る乗客を選ぶ時、現在の位置で最も短い距離の乗客を選ぶ.このような乗客が多い場合は、その中で一番小さい番号の乗客を選び、そのような乗客が多い場合は、その中で一番小さい番号の乗客を選びます.タクシーと乗客が同じ位置に立っている場合、その乗客までの最短距離はゼロです.燃料は1コマ移動するごとに消費される.1人の乗客を目的地に移動することに成功すると、その乗客が移動中に消費する燃料量は2倍に増加する.移動途中で燃料が切れて移動が失敗し、当日の作業が終了します.乗客を目的地に移すと同時に、燃料が尽きた場合は失敗しない.
<図1>タクシーが活動するエリアを示す地図で、タクシーと3人の乗客の出発地と目的地を示す.タクシーの現在の燃料量は15です.現在、タクシーから乗客1人あたりの最短距離は9、6、7なので、タクシーは2番の乗客の出発地に向かいます.
<図2>タクシーから2番乗客の出発地までの経路を示し、<図3>2番乗客の出発地から目的地までの経路を示す.目的地に移動する前に消費される燃料は6であり、移動後に12を充電するので、残りの燃料量は15である.現在、タクシーから乗客1人あたりの最短距離は7つなので、タクシーは2つの中でもっと小さい1番の乗客の出発地に移動します.
<図4>及び<図5>は、タクシー1号の乗客が目的地へ向かう経路を示す.余剰燃料量15-7-7+7×2=15.
<図6>および<図7>は、タクシー3号の乗客が目的地に向かう経路を示す.最終残存燃料量15-5-4+4+4×2=14.
すべての乗客を正常に送ることができるかどうかを見つけて、送ることができるならば、プログラムを書いて最終的な余剰燃料の量を出力してください.
入力
第1列は、N、Mおよび初期燃料の量を与える.(2≦N≦20,1≦M≦N 2,1≦初期燃料≦500000)燃料は無限に充填できるので、初期燃料の量を超えて満タンになる可能性がある.
次の行から、N行において、伯俊活動領域の地図が与えられる.0はスペース、1は壁です.
次の行は白俊が運転を始めた車両の行番号と列番号を示した.行と列番号は1以上N以下の自然数で、運転を開始したのはスペースです.
次の行から、各乗客の出発地の行と列番号、および目的地の行と列番号.すべての出発地と目的地は空いていて、出発地ごとに異なり、お客様の出発地と目的地ごとに異なります.
しゅつりょく
すべてのお客様を動員し、燃料が満たされたときに残りの燃料の量を出力します.しかし、移動途中で燃料が尽き、次の出発地または目的地に移動できない場合は、−1が出力される.すべてのお客様を移動できなくても、-1を出力します.
これはBFS+シミュレーションタイプの問題である.
壁がなければ簡単に行・列座標で距離を計算できますが、壁があるのでBFSで最短距離を求めます.
その後、乗客を乗せて、目的地に移動し、燃料の部分を変えて、問題のように表現すればよい.
問題を解く順番は以下の通りです.タクシーの位置を基準にBFSで距離を求めます. 乗っていない乗客名を対象に、最寄りの乗客を探しています. 街近くで運賃の小さい乗客を選んだ. 行が同じであれば、熱値の小さい乗客を選択します. の余剰燃料と乗客との距離を比較する. は、余剰燃料<乗客距離−出力−1が停止している場合に行う. の場合、燃料残量>乗客距離、燃料残量−乗客距離. の乗客位置を基準にBFSで距離を求める. に搭載された乗客番号と同じ目的地までの距離を見つける. は、余剰燃料<目的地までの距離−1出力が停止している場合に行う. 余剰燃料>目的地までの距離であれば、余剰燃料+目的地までの距離である.乗客を目的地に乗せた後、対応する乗客番号に表示を完了し、タクシーの行、列を更新する. コードは次のとおりです.
📌問題の説明
StartLinkは「StartTaxi」というタクシー事業を開始した.タクシーを起動するのは特別で、お客さんを目的地に送るたびに燃料が充電され、燃料が切れた当日の仕事は終わります.
タクシー運転手の崔伯俊さんは今日、M人の乗客を乗せることを目標にしています.白俊が活動する分野はNだ.×Nサイズのメッシュで表すことができ、各セルが空または壁になっています.タクシーが空席の場合、上下左右に隣接する空席の一つに移動できます.アルゴリズム経験豊富なBaek Junは,特定の位置に移動すると常に最短経路に移動する.
M人の乗客は1つのスペースに立って、別のスペースの1つに移動する準備をしています.複数の乗客が一緒に搭乗する場合はありません.そのため、白俊は乗客1人を乗せて目的地に向かうM回を繰り返した.乗客一人一人が動かず、出発地でタクシーに乗るしかなく、目的地の地下タクシーに乗るしかありません.
白俊が乗る乗客を選ぶ時、現在の位置で最も短い距離の乗客を選ぶ.このような乗客が多い場合は、その中で一番小さい番号の乗客を選び、そのような乗客が多い場合は、その中で一番小さい番号の乗客を選びます.タクシーと乗客が同じ位置に立っている場合、その乗客までの最短距離はゼロです.燃料は1コマ移動するごとに消費される.1人の乗客を目的地に移動することに成功すると、その乗客が移動中に消費する燃料量は2倍に増加する.移動途中で燃料が切れて移動が失敗し、当日の作業が終了します.乗客を目的地に移すと同時に、燃料が尽きた場合は失敗しない.
<図1>タクシーが活動するエリアを示す地図で、タクシーと3人の乗客の出発地と目的地を示す.タクシーの現在の燃料量は15です.現在、タクシーから乗客1人あたりの最短距離は9、6、7なので、タクシーは2番の乗客の出発地に向かいます.
<図2>タクシーから2番乗客の出発地までの経路を示し、<図3>2番乗客の出発地から目的地までの経路を示す.目的地に移動する前に消費される燃料は6であり、移動後に12を充電するので、残りの燃料量は15である.現在、タクシーから乗客1人あたりの最短距離は7つなので、タクシーは2つの中でもっと小さい1番の乗客の出発地に移動します.
<図4>及び<図5>は、タクシー1号の乗客が目的地へ向かう経路を示す.余剰燃料量15-7-7+7×2=15.
<図6>および<図7>は、タクシー3号の乗客が目的地に向かう経路を示す.最終残存燃料量15-5-4+4+4×2=14.
すべての乗客を正常に送ることができるかどうかを見つけて、送ることができるならば、プログラムを書いて最終的な余剰燃料の量を出力してください.
入力
第1列は、N、Mおよび初期燃料の量を与える.(2≦N≦20,1≦M≦N 2,1≦初期燃料≦500000)燃料は無限に充填できるので、初期燃料の量を超えて満タンになる可能性がある.
次の行から、N行において、伯俊活動領域の地図が与えられる.0はスペース、1は壁です.
次の行は白俊が運転を始めた車両の行番号と列番号を示した.行と列番号は1以上N以下の自然数で、運転を開始したのはスペースです.
次の行から、各乗客の出発地の行と列番号、および目的地の行と列番号.すべての出発地と目的地は空いていて、出発地ごとに異なり、お客様の出発地と目的地ごとに異なります.
しゅつりょく
すべてのお客様を動員し、燃料が満たされたときに残りの燃料の量を出力します.しかし、移動途中で燃料が尽き、次の出発地または目的地に移動できない場合は、−1が出力される.すべてのお客様を移動できなくても、-1を出力します.
💡 問題を解く
これはBFS+シミュレーションタイプの問題である.
壁がなければ簡単に行・列座標で距離を計算できますが、壁があるのでBFSで最短距離を求めます.
その後、乗客を乗せて、目的地に移動し、燃料の部分を変えて、問題のように表現すればよい.
問題を解く順番は以下の通りです.
import sys
from copy import deepcopy
from collections import deque
d = [(0, 1), (0, -1), (1, 0), (-1, 0)]
def pick(distance):
man = -1 # 선택한 승객의 번호
now = int(1e9)
for idx in range(M):
if not done[idx]:
r, c = customer[idx][0], customer[idx][1]
if distance[r][c] < now: # 거리가 작으면 갱신
now = distance[r][c]
man = idx
elif distance[r][c] == now: # 거리가 같으면
if r < customer[man][0]: # 행 값이 작은 승객을 선택
man = idx
elif r == customer[man][0]: # 행 값도 같으면
if c < customer[man][1]: # 열 값이 작은 승객을 선택
man = idx
return man
def bfs(tr, tc): # 최단 거리 구하기
queue = deque([(tr, tc)])
distance = deepcopy(origin) # 거리를 표시할 행렬
distance[tr][tc] = 1
while queue:
r, c = queue.popleft()
for idx in range(4):
nr = r + d[idx][0]
nc = c + d[idx][1]
if 0 <= nr < N and 0 <= nc < N:
if not distance[nr][nc]:
queue.append((nr, nc))
distance[nr][nc] = distance[r][c] + 1
return distance
N, M, fuel = map(int, input().split())
origin = [list(map(int, sys.stdin.readline().split())) for _ in range(N)]
customer = []
tr, tc = map(int, input().split()) # 택시의 행, 열
tr -= 1; tc -= 1 # 인덱스는 0부터 이므로 1씩 빼주었다.
for _ in range(M):
sr, sc, er, ec = map(int, input().split())
customer.append((sr-1, sc-1, er-1, ec-1)) # 승객의 행, 열 / 목적지의 행, 열
done = [False] * M # 승객 탑승 여부를 알려주는 배열
while done.count(False): # 모든 승객을 이동시키지 않았다면 아래의 내용을 반복
distance = bfs(tr, tc) # 택시 ~ 승객 거리 찾기
man = pick(distance) # 가까운 승객 선택
dist_man = distance[customer[man][0]][customer[man][1]] # 승객까지의 거리
if not dist_man or fuel < dist_man - 1: # 만약 벽으로 인해 갈 수 없거나 남은 연료보다 거리가 더 크면
fuel = -1 # -1을 출력하고 탐색 중지
break
fuel -= (dist_man - 1) # 이동이 가능하면 연료값 최신화
distance = bfs(customer[man][0], customer[man][1]) # 택시(with 승객) ~ 목적지 거리 찾기
dist_goal = distance[customer[man][2]][customer[man][3]] # 목적지 까지 거리
if not dist_goal or fuel < dist_goal - 1: # 이동 가능 여부 확인
fuel = -1
break
fuel += dist_goal - 1 # 연료값 최신화
done[man] = True # 승객 이동 여부 최신화
tr, tc = customer[man][2], customer[man][3] # 택시 위치(행, 열) 최신화
print(fuel)
乗客を目的地に移動するにはBFSを2回行う必要があるため,メモリを増やすことでBFS探索の時間的複雑さを低減しようとしたが,このコードも完全に通過できる.👍Reference
この問題について([Algorithm] BaekJoon : 19238. タクシー台), 我々は、より多くの情報をここで見つけました https://velog.io/@djagmlrhks3/Algorithm-BaekJoon-19238.-스타트-택시-by-Pythonテキストは自由に共有またはコピーできます。ただし、このドキュメントのURLは参考URLとして残しておいてください。
Collection and Share based on the CC Protocol