-
Notifications
You must be signed in to change notification settings - Fork 4
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #141 from IJS1016/main
[24.04.2W]python ps, codetree
- Loading branch information
Showing
5 changed files
with
585 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,99 @@ | ||
def get_distance_from_r() : | ||
d_list = [] # [d, r, c, idx] # d min으로 정렬, r max, c max로 정렬하기 위해서! d를 -해주면 정렬이 가능 | ||
for idx, (sr, sc) in enumerate(santas) : | ||
if santa_status[idx] >= 0 : | ||
d = ((sr - rr) ** 2 + (sc - rc) ** 2) | ||
d_list.append([idx, d, sr, sc]) | ||
d_list.sort(key=lambda x:(x[1], -x[2], -x[3])) # d, min으로 정렬 r max, c max 정렬 | ||
return d_list[0] | ||
|
||
def get_distance_from_s(sr, sc) : # td이 d보다 작아서 가까워질때만 d_list에 넣어줌, idx는 direction 우선순위 | ||
direction = [[-1, 0], [0, 1], [1, 0], [0, -1]] # 상우하좌 | ||
d_list = [] | ||
d = ((sr - rr) ** 2 + (sc - rc) ** 2) # 기존 거리보다 작아야됨 | ||
for idx, (dr, dc) in enumerate(direction) : | ||
td = ((sr + dr - rr) ** 2 + (sc + dc - rc) ** 2) | ||
if d > td : | ||
d_list.append([idx, td, dr, dc]) | ||
d_list.sort(key=lambda x:(x[1], x[0])) | ||
return d_list | ||
|
||
def push_santa(tsr, tsc, mr, mc, sidx) : # 산타가 이동하는 좌표 tsr, tsc 받아서, push 해줌 | ||
if 1 <= tsr <= N and 1 <= tsc <= N: # 범위내 있으면 산타 index 변경, 기절 상태로 변경 | ||
for siidx, santa in enumerate(santas): # 산타 위치 돌면서 자리에 산타 있는지 확인 | ||
if [tsr, tsc] == santa and sidx != siidx: # 산타 겹치는 경우 | ||
santas[sidx] = [tsr, tsc] # 기존 산타를 이동 | ||
push_santa(tsr+mr, tsc+mc, mr, mc, siidx) # 이동할 산타 옮기기 | ||
break | ||
santas[sidx] = [tsr, tsc] | ||
else : # 탈락 라운드 작성(나중에 점수에 +하면 됨), 근데 기절상태라면,,? <0일때만 +로 바꿔주는 함수 넣기 | ||
santas[sidx] = [-N, -N] # 존재하지 않는 위치로 변경, distance 가장 높게 나오기 위해서 -N? | ||
santa_status[sidx] = -m | ||
# 입력 ########################################################### | ||
N, M, P, C, D = map(int, input().split(" ")) | ||
rr, rc = map(int, input().split(" ")) | ||
|
||
santas = [] | ||
santa_status = [0] * P # -(퇴장라운드), 0, +(기절) 퇴장, 정상, 기절 | ||
santa_score = [0] * P # score | ||
|
||
for _ in range(P) : | ||
santas.append(list(map(int, input().split(" ")))) | ||
santas.sort(key = lambda x : x[0]) | ||
santas = [s[1:] for s in santas] # santas [sr, sc]이고 1번부터 P까지 순서대로 있음 | ||
###################################################################### | ||
|
||
for m in range(1, M+1) : # 1번-M번 턴, 남은 산타에 대해서만 +1점 | ||
# 기절 산타들 풀어주기 | ||
for i in range(P) : | ||
if santa_status[i] > 0 : | ||
santa_status[i] -= 1 | ||
# 루돌프 이동, 산타와 가까워지는 방향으로 | ||
sidx, dx, sr, sc = get_distance_from_r() # d_list에서 산타 존재하면, 충돌! | ||
dr = (sr - rr) / abs(sr - rr) if rr - sr != 0 else 0 | ||
dc = (sc - rc) / abs(sc - rc) if rc - sc != 0 else 0 | ||
rr = rr + dr | ||
rc = rc + dc | ||
# 충돌 발생 | ||
if [rr, rc] in santas : | ||
santa_score[sidx] += C | ||
tsr, tsc = santas[sidx][0] + dr * C, santas[sidx][1] + dc * C # 루돌프 이동 방향으로 C칸 물러남 | ||
if 1 <= tsr <= N and 1 <= tsc <= N : # 범위내 있으면 산타 index 변경, 기절 상태로 변경 | ||
santa_status[sidx] = 2 | ||
push_santa(tsr, tsc, dr, dc, sidx) | ||
else : # 탈락 라운드 작성(나중에 점수에 +하면 됨), 근데 기절상태라면,,? <0일때만 +로 바꿔주는 함수 넣기 | ||
santas[sidx] = [-N, -N] # 존재하지 않는 위치로 변경 | ||
santa_status[sidx] = -m | ||
|
||
# 산타 거리 계산 후 이동 ###########################3 | ||
# 산타 거리 계산할 때...상우하좌 | ||
for sidx in range(P): | ||
if santa_status[sidx] == 0: # 정상일 때만 이동 | ||
sr, sc = santas[sidx] | ||
condi_list = get_distance_from_s(sr, sc) | ||
mr, mc = 0, 0 | ||
for condi in condi_list : | ||
_, _, dr, dc = condi | ||
if [sr+dr, sc+dc] not in santas : | ||
mr, mc = dr, dc # 이동 확정 | ||
break | ||
# 산타 이동 | ||
sr, sc = sr + mr, sc + mc | ||
if [sr, sc] == [rr, rc] : # 루돌프와 충돌 발생 확인, 루돌프는 반드시 map 범위 안에 있으니 추가 검사 필요하지 않음 | ||
santa_score[sidx] += D | ||
tsr, tsc = sr + mr * (-D), sc + mc * (-D) | ||
santa_status[sidx] = 2 # 기절 | ||
push_santa(tsr, tsc, -mr, -mc, sidx) | ||
else : | ||
santas[sidx] = [sr, sc] | ||
|
||
if max(santa_status) < 0 : | ||
break | ||
|
||
# 출력 ############################################# | ||
for sidx in range(P) : | ||
if santa_status[sidx] < 0 : # 탈락 산타만 탈락 라운드 점수 더해주기 | ||
santa_score[sidx] -= (santa_status[sidx]+1) | ||
else : | ||
santa_score[sidx] += M # 탈락하지 않은 산타는 M 라운드 더해주고 | ||
print(santa_score[sidx], end=" ") |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,168 @@ | ||
# 입력) | ||
# N, M, K | ||
# NxN 미로 정보) 0, (1-9) 벽 | ||
# M 참가자 좌표) 초기에는 빈칸에만 존재 | ||
# 출구 좌표 -> 빈칸... | ||
|
||
# 출력) 모든 참가자들의 이동 거리 합과 출구 좌표를 출력 | ||
class Point : | ||
def __init__(self, r, c): | ||
self.r = r-1 | ||
self.c = c-1 | ||
|
||
# 입력 받으면서 -1해서 범위 (0, N-1)로 변경 | ||
# 입력 받기 ################################################ | ||
N, M, K = map(int, input().split(" ")) | ||
mmap = [] | ||
persons = [] | ||
person_status = [True] * M | ||
total_move = 0 | ||
for _ in range(N) : | ||
mmap.append(list(map(int, input().split(" ")))) | ||
for _ in range(M) : | ||
r, c = map(int, input().split(" ")) | ||
persons.append(Point(r, c)) | ||
r, c = map(int, input().split(" ")) | ||
exit_p = Point(r, c) | ||
####################################################### | ||
def get_distance(r, c) : | ||
return(abs(exit_p.r-r)+abs(exit_p.c-c)) | ||
|
||
def check_out_mmap(r, c) : | ||
if (0 <= r < N) and (0 <= c < N) : | ||
return True | ||
return False | ||
|
||
def persons_move() : | ||
# 모든 참가자 이동 - 벽 없는 곳, 가까워지는 곳, 우선순위 상하, 중첩 가능, 이동 횟수 +1, 출구 이동 시 탈출 | ||
global total_move | ||
directions = [[-1, 0], [1, 0], [0, -1], [0, 1]] # 우선순위 상하 | ||
for i, p in enumerate(persons) : | ||
if person_status[i] : | ||
od = get_distance(p.r, p.c) # 이동 전 distance 계산, original_distance : od | ||
for drt in directions : | ||
dr, dc = drt | ||
nr, nc = p.r + dr, p.c + dc | ||
if check_out_mmap(nr, nc) and mmap[nr][nc] == 0: # 맵을 나가지 않고, 벽이 없으면 | ||
if od > get_distance(nr, nc) : # 새롭게 얻은 거리가 더 작으면 | ||
persons[i].r, persons[i].c = nr, nc # 사람 이동 | ||
total_move += 1 | ||
break # DBG) 새롭게 얻은 거리가 더 작으면? 무조건 1차이 아님? 틀리면 break 빼기 | ||
if [persons[i].r, persons[i].c] == [exit_p.r, exit_p.c] : # 출구 이동 시 탈출, REVIEW : class 비교 꺼내서 해야됨 바로 X | ||
person_status[i] = False | ||
|
||
# 정사각형을 어떻게 잡을지 | ||
# 같은 사람을 포함하는 정사각형이 어려개 있을 수 있음 | ||
# 크기 먼저..., r,c 범위 | ||
# DBG) 맵 범위? 상관 있음 - 사람이 오른쪽 하단에? 상관 없나..? 우선 해보고 틀리면 생각 | ||
# mmap slicing할 떄 범위 [min_r, max_r+1] 주의 | ||
def search_rectangle() : | ||
er, ec = exit_p.r, exit_p.c | ||
rectangles = [] # [l, r, c]로 저장 | ||
dlist = [] | ||
for i, p in enumerate(persons) : | ||
if person_status[i] : | ||
dr, dc = p.r - er, p.c - ec # P - E | ||
l = max([abs(dr), abs(dc)]) # 정사각형 길이(3이면 2가 저장됨에 유의) | ||
# p에서 좌상단 할 수 있는 케이스 4개 확인 | ||
# [0, 0], [0, l], [l, 0], [0, -l], [-l, 0], # REVIEW : 범위 제대로 | ||
for dlr in range(-l, l+1) : | ||
for dlc in range(-l, l+1) : | ||
# dlr, dlc = dl # 좌상단 좌표 찾기 위해서... | ||
tr, tc = er + dlr, ec + dlc # 출구 기준 좌상단 tr, tc | ||
if check_out_mmap(tr, tc) and tr <= p.r <= tr + l and tc <= p.c <= tc + l : # 범위 내 사람이 있으면 | ||
rectangles.append([l, tr, tc]) | ||
tr, tc = p.r + dlr, p.c + dlc # 사람 기준 좌상단 tr, tc | ||
if check_out_mmap(tr, tc) and tr <= er <= tr + l and tc <= ec <= tc + l: # 범위 내 사람이 있으면 | ||
rectangles.append([l, tr, tc]) | ||
# 최종 sort | ||
rectangles.sort(key=lambda x : (x[0], x[1], x[2])) # 길이 작은 순, r, c 좌표 작은 우선순위 | ||
return rectangles[0] | ||
|
||
def check_inside_rect(rr, rc, rl, r, c) : | ||
if rr <= r <= rr + rl and rc <= c <= rc + rl: | ||
return True | ||
return False | ||
def rotate_rectangle(rl, rr, rc) : | ||
rotated_infos = [] # 회전된 r, c, value 순으로 저장 | ||
# 맵 회전 정보 저장 | ||
for tr, line in enumerate(mmap) : | ||
for tc, v in enumerate(line) : | ||
if check_inside_rect(rr, rc, rl, tr, tc) : | ||
# if rr <= tr <= rr + rl and rc <= tc <= rc + rl : | ||
rotated_infos.append([tc - rc + rr, rl - (tr - rr) + rc, max(v-1, 0)]) # shift | ||
if DBG : | ||
print(f"ROTATED ({rr}, {rc}), size {rl}") | ||
# print("rotated_infos") | ||
# for ri in rotated_infos : | ||
# print(ri) | ||
# 저장된 회전 정보 맵에 써주기 | ||
for info in rotated_infos : | ||
r, c, v = info | ||
mmap[r][c] = v | ||
# exit, person 회전 | ||
for i, p in enumerate(persons) : | ||
if person_status[i] : | ||
if check_inside_rect(rr, rc, rl, p.r, p.c) : | ||
persons[i].r, persons[i].c = p.c - rc + rr, rl - (p.r - rr) + rc # DBG) person[i]말고 p.c = 없는지, 이렇게 해도 되는지 확인하기 | ||
exit_p.r, exit_p.c = exit_p.c - rc + rr, rl - (exit_p.r - rr) + rc | ||
|
||
|
||
def print_mmap() : | ||
print(" ", end="") | ||
for i in range(N) : | ||
print(change_color_y(f" {i}"), end="") | ||
print() | ||
for i, m in enumerate(mmap) : | ||
print(change_color_y(f"{i} "), end="") | ||
ptr_str = '' | ||
for j, mm in enumerate(m) : | ||
flag = True | ||
if [exit_p.r, exit_p.c] == [i, j] : | ||
ptr_str += change_color_b(f"{mm}") + " " | ||
flag = False | ||
for pi, p in enumerate(persons): | ||
if person_status[pi]: | ||
if [p.r, p.c] == [i, j] : | ||
ptr_str += change_bg(f"{mm}") + " " | ||
flag = False | ||
break | ||
if flag : | ||
ptr_str += f"{mm} " | ||
print(ptr_str) | ||
|
||
def change_color_y(s) : | ||
return '\033[31m' + str(s) + '\033[0m' | ||
def change_color_b(s) : | ||
return '\033[34m' + str(s) + '\033[0m' | ||
def change_bg(s) : | ||
return '\033[43m' + str(s) + '\033[0m' | ||
|
||
bm = 0 | ||
DBG = False | ||
for k in range(K) : # K번 실행 | ||
if DBG : | ||
print(f"\n\n!! {k+1}초") | ||
print("before rot") | ||
print_mmap() | ||
persons_move() | ||
if DBG : | ||
print(f"people move {total_move-bm}") | ||
print_mmap() | ||
|
||
if not max(person_status) : | ||
if DBG : print("NO PP") | ||
break | ||
|
||
# 회전할 정사각형 서치 - 사람 한 명이라도 포함해야함, 크기 작은 순, 좌상단 r, c 작은 순 우선 | ||
rl, rr, rc = search_rectangle() # rectangle, 이때 길이 3이면 rl에는 2가 저장 | ||
# 정사각형 회전 - 출구, 포함된 사람, 벽 모두 회전 => 시계 방향 회전 | ||
rotate_rectangle(rl, rr, rc) # 시계 방향 회전을 어떻게 구현(C, N-R) | ||
if DBG: | ||
bm = total_move | ||
print(f"{k+1} after rot") | ||
print_mmap() | ||
# 사람들 없으면 break | ||
|
||
print(total_move) | ||
print(exit_p.r+1, exit_p.c+1) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,122 @@ | ||
# 입력 | ||
# L N Q # L : 체스판 크기, N : 기사 수, Q : 명령 | ||
# L개 줄에 겹쳐 LxL 체스판 정보, 0 : 빈칸, 1 : 함정, 2: 벽 | ||
# N명 기사 정보(순서대로) : r, c, h, w, k - 위치 (r, c), 방패 (h, w) 체력 k | ||
# Q개 명령 : i, d i번째 기사 d로 한칸 이동(사라진 기사 번호가 주어질 수 있음) | ||
# d (0, 1, 2, 3) : 상 우 하 좌 | ||
# 처음에는 기사들끼리 겹쳐지지 않고, 기사와 벽은 겹쳐서 주어지지 않음 | ||
|
||
# 출력 | ||
# Q 명령 후 생존 기사들의 받은 총 데미지 합 | ||
|
||
DBG = False | ||
class Knight : | ||
def __init__(self, r, c, h, w, k): | ||
self.r = r | ||
self.c = c | ||
self.h = h # 방패 바로 더해주려고 -1 해줌, 인덱싱할 땐 그냥 써야되네;... | ||
self.w = w | ||
self.k = k | ||
self.d = 0 | ||
self.status = True | ||
def get_infos(self): | ||
return [self.r, self.c, self.h, self.w] | ||
|
||
# 입력 ################################################ | ||
L, N, Q = map(int, input().split(" ")) | ||
mmap = [] | ||
knights = [] | ||
orders = [] | ||
total_damage = [0] * N | ||
for _ in range(L) : | ||
mmap.append(list(map(int, input().split(" ")))) | ||
for _ in range(N) : | ||
r, c, h, w, k = map(int, input().split(" ")) | ||
knights.append(Knight(r, c, h, w, k)) | ||
for _ in range(Q) : | ||
orders.append(map(int, input().split(" "))) | ||
###################################################### | ||
|
||
def check_mapout(r, c, h, w) : | ||
if 1 <= r <= L and 1 <= c <= L and 1 <= r+h-1 <= L and 1 <= c+w-1 <= L : | ||
return True | ||
return False | ||
def check_overlap(tr, tc, h, w, other_knight) : | ||
ot_r, ot_c, ot_h, ot_w = other_knight.get_infos() | ||
# 잘못!! 어떤게 더 클지 모르니까 둘다 해줘야되네... | ||
if (tr <= ot_r <= tr+h-1) or (tr <= ot_r+ot_h-1 <= tr+h-1) : # 세로 방향 겹치는지 | ||
if (tc <= ot_c <= tc+w-1) or (tc <= ot_c+ot_w-1 <= tc+w-1): # 가로 방향 겹치는지 | ||
return True | ||
if (ot_r <= tr <= ot_r+ot_h-1) or (ot_r <= tr+h-1 <= ot_r+ot_h-1): # 세로 방향 겹치는지 | ||
if (ot_c <= tc <= ot_c+ot_w-1) or (ot_c <= tc+w-1 <= ot_c+ot_w-1): # 가로 방향 겹치는지 | ||
return True | ||
|
||
return False | ||
|
||
def get_max_value(tr, tc, h, w) : | ||
max_value = 0 | ||
for m in mmap[tr - 1:tr + h - 1] : # tr이 1부터 시작하니까 | ||
tmp = max(m[tc - 1:tc + w - 1]) | ||
if max_value < tmp : | ||
max_value = tmp | ||
return max_value | ||
|
||
def get_damage(r, c, h, w) : | ||
damage = 0 | ||
for m in mmap[r - 1:r + h - 1] : | ||
for v in m[c - 1:c + w - 1] : | ||
if v == 1 : damage+=1 | ||
return damage | ||
|
||
# 뭐가 하나라도 안되면 False로 return해서 돌지 않도록 | ||
# 최종으로 된다고 하면 True랑 history return해서 위치 바꿔주면서 패널티 세기 | ||
def push_knights(knight, kidx, move, history): | ||
# 이동 시 밀 수 있는지 검사 | ||
mr, mc = move | ||
tr, tc = knight.r+mr, knight.c+mc | ||
h, w = knight.h, knight.w | ||
if not check_mapout(tr, tc, h, w) : # 맵 범위 밖이거나 | ||
if DBG :print(f"NO! knight {kidx+1} - map out") | ||
return False, history # 이동 불가 | ||
elif get_max_value(tr, tc, h, w) == 2 : # 벽이 있으면 | ||
if DBG : print(f"NO! knight {kidx+1} - wall") | ||
return False, history | ||
# 이동 불가 | ||
else : # 벽이 없다면 이동 가능 | ||
if DBG :print(f"GO! knight {kidx+1}") | ||
history[kidx] = [tr, tc] # new tr, tc | ||
for idx, other_knight in enumerate(knights): # 기사가 있는지 검사 | ||
if other_knight.status : # 기사가 살아있을 때 | ||
if idx != kidx and idx not in history.keys(): # 자기 자신이 아니고 다른 기사랑 만났을 때, 본 것들이 아닐 때 | ||
if DBG : print(f"-> check knight {idx+1}") | ||
if check_overlap(tr, tc, h, w, other_knight) : # 겹치는 영역이 있으면 | ||
if DBG: print(f"overlap knight {idx + 1} info {other_knight.r, other_knight.c, other_knight.h, other_knight.w}") | ||
flag, history = push_knights(other_knight, idx, [mr, mc], history) # 다시 밀어내기 | ||
if not flag : | ||
return False, None | ||
return True, history | ||
|
||
direct = ['상', '우', '하', '좌'] | ||
directions = [[-1, 0], [0, 1], [1, 0], [0, -1]] # 상우하좌 | ||
for (kidx, d) in orders : | ||
kidx -= 1 | ||
if DBG : print(f"!!! Order Knight : {kidx+1}, {direct[d]}") | ||
if knights[kidx].status : # 기사가 살아있으면 | ||
flag, history = push_knights(knights[kidx], kidx, directions[d], {}) | ||
if DBG : print(flag, history) | ||
if flag : | ||
for hkidx, (nr, nc) in history.items() : # 좌표 업데이트, 업데이트 하면서 패널티도 받게 하기 | ||
knights[hkidx].r, knights[hkidx].c = nr, nc # 좌표값 업데이트 | ||
if hkidx != kidx: # 명령 아닌거만 패널티 | ||
h, w = knights[hkidx].h, knights[hkidx].w # 쉽게 쓸라고, 노의미 | ||
knights[hkidx].d += get_damage(nr, nc, h, w) | ||
if knights[hkidx].k <= knights[hkidx].d : | ||
knights[hkidx].status = False | ||
|
||
result = 0 | ||
for kidx, knight in enumerate(knights) : | ||
if knight.status : | ||
if DBG : print(f"{kidx+1}D : {knight.d}") | ||
result += knight.d | ||
|
||
print(result) |
Oops, something went wrong.