1+ """
2+ BFS , 구현 , 시뮬레이션
3+ """
4+ #상 o, 우상, 우, 우하 , 하, 좌하, 좌, 좌상
5+ di = [- 1 ,- 1 ,0 ,1 ,1 ,1 ,0 ,- 1 ]
6+ dj = [0 ,1 ,1 ,1 ,0 ,- 1 ,- 1 ,- 1 ]
7+ #디버깅 용
8+ def myprint (arr ):
9+ for lst in arr :
10+ print (* lst ) # 2행 리시트는 1열이 1 instacne
11+ print ()
12+
13+ # [0] BFS 로 메듀사 최단경로 : 도로 따라 공원까지 - 상하좌우
14+ # route = find_route(si,sj,ei,ej)
15+ from collections import deque
16+ def find_route (si ,sj ,ei ,ej ):
17+ q = deque ()
18+ v = [ [0 ]* N for _ in range (N )] # 방문 여부 & *직전 위치*
19+
20+ q .append ((si ,sj ))
21+ v [si ][sj ] = (si ,sj ) # 직전 위치 저장
22+
23+ while q :
24+ ci , cj = q .popleft ()
25+
26+ # 목적지 도착 -> 경로 저장
27+ if (ci ,cj )== (ei ,ej ) :
28+
29+ route = []
30+ ci ,cj = v [ci ][cj ]
31+ while (ci ,cj ) != (si ,sj ): # 출발지가 아니면 저장
32+ route .append ((ci ,cj ))
33+ ci ,cj = v [ci ][cj ]
34+ return route [::- 1 ] #역순(메듀사 이동 start- > end 순서대로)
35+
36+ # 4방향(상하좌우), 범위내 , 미방문 ,조건(==0)
37+ for di ,dj in ((- 1 ,0 ),(1 ,0 ),(0 ,- 1 ),(0 ,1 )):
38+ ni , nj = ci + di , cj + dj
39+ if 0 <= ni < N and 0 <= nj < N and v [ni ][nj ]== 0 and arr [ni ][nj ] == 0 :
40+ q .append ((ni ,nj ))
41+ v [ni ][nj ] = (ci ,cj ) # 바로 이전 좌표 저장
42+
43+ #여기까지 오면? : 목적지 못찾음
44+ return - 1
45+
46+
47+ # mark_line(v,ni,nj,dr)
48+ def mark_line (v ,ci ,cj ,dr ): # dir 방향 직선으로 : M ~>1 "w ~2"
49+
50+ while 0 <= ci < N and 0 <= cj < N : # 범위 나가는걸 방지
51+ v [ci ][cj ] = 2 # 시각적 구분을 위해 2로 표기 = safe 존
52+ ci ,cj = ci + di [dr ],cj + dj [dr ] # 다음 dr 방향 칸 이동
53+
54+
55+
56+ def mark_safe (v ,si ,sj ,dr ,org_dr ): # si ,sj : 전사 위치
57+ #[1] 직선방향표기
58+ ci ,cj = si + di [dr ], sj + dj [dr ]
59+
60+ mark_line (v ,ci ,cj ,dr ) # v에 dr방향으로 이동 가능 지역 표시
61+
62+ #[2]전사가 바라보는 방향으로 한줄 식 표시 : 전사에게 가려져 이동 가능 지역
63+ ci ,cj = si + di [org_dr ],sj + dj [org_dr ] # 이동한 svf poin 초기화
64+
65+ while 0 <= ci < N and 0 <= cj < N : # 범위내라면 계속 진행
66+ mark_line (v ,ci ,cj ,dr )
67+ ci ,cj = ci + di [org_dr ],cj + dj [org_dr ] # org_dir로 point(대각선) 위치 이동
68+
69+
70+ # tv , tstone = make_stone(marr , mi , mj dr) >>>tv , tston
71+
72+ def make_stone (marr , mi ,mj ,dr ):
73+ v = [[0 ]* N for _ in range (N )]
74+ cnt = 0 # stone된 병사 개수
75+
76+ # myprint(marr)
77+ #[1] dr 방향으로 w(>0) 만날때 까지 1 표시 , 이후 2 표시
78+ ni , nj = mi + di [dr ] , mj + dj [dr ]
79+
80+ while 0 <= ni < N and 0 <= nj < N : # 범위내리면서 계속 진행
81+ v [ni ][nj ] = 1
82+
83+ if marr [ni ][nj ] > 0 : # 병사 w 만남
84+ cnt += marr [ni ][nj ] # 해당 영역의 모든 w 석화
85+ ni , nj = ni + di [dr ] , nj + dj [dr ] # 다음 칸으로 이동
86+
87+ mark_line (v ,ni ,nj ,dr ) # v에 dr 방향으로 이동 가능 지역 표시
88+
89+ break
90+ ni , nj = ni + di [dr ] , nj + dj [dr ]
91+ #[2] dr -1 ,dr +1 방향으로 M의 시선 동일 처리, 대각선 원점 잡고 dr 방향으로 처리
92+ for org_dr in ((dr - 1 )% 8 , (dr + 1 )% 8 ):
93+ si ,sj = mi + di [org_dr ], mj + dj [org_dr ] # 첫 대각선 위치부터 체크
94+
95+ # 대각선 시야각 영역 확인
96+ while 0 <= si < N and 0 <= sj < N : # 대각선 방향으로 초기 위치 탐색 후 직선 시선
97+ if v [si ][sj ] == 0 and marr [si ][sj ]> 0 : # 전사 만남
98+ v [si ][sj ] = 1
99+ cnt += marr [si ][sj ]
100+ mark_safe (v ,si ,sj ,dr ,org_dr ) # 전사가 바라보는 방향으로 safe(이동 가능 범위) 표시
101+ break
102+ # W 가 길 중간에 있는 경우
103+ ci ,cj = si ,sj # 첫 위치가 전사가 아닐 경우는 직선으로
104+ while 0 <= ci < N and 0 <= cj < N : # 범위 내리면서 계속 진행
105+ if v [ci ][cj ]== 0 : # 처음 방문
106+ v [ci ][cj ] = 1
107+ if marr [ci ][cj ]> 0 : # 전사로 막히면
108+ cnt += marr [ci ][cj ]
109+ mark_safe (v , ci ,cj ,dr ,org_dr ) # v에서 dr 방향으로 이동 가능 지역 표시
110+ break
111+ else :
112+ break
113+ ci ,cj = ci + di [dr ], cj + dj [dr ]
114+
115+ si ,sj = si + di [org_dr ], sj + dj [org_dr ]
116+ return v , cnt
117+
118+ # move_cnt , attk_cnt = move_men(v,mi,mj)
119+
120+ def move_men (v ,mi ,mj ) :
121+ # [3] 전사의 이동 - (상하좌우)(좌우상하) 메두사 시야 아니면 (!=1)
122+ move , attk = 0 ,0
123+ for dirs in (((- 1 ,0 ),(1 ,0 ),(0 ,- 1 ),(0 ,1 )), ((0 ,- 1 ),(0 ,1 ),(- 1 ,0 ),(1 ,0 ))):
124+ for idx in range (len (men )- 1 ,- 1 ,- 1 ):
125+ ci ,cj = men [idx ]
126+ if v [ci ][cj ] == 1 : # 메듀사 시야 내에 있으면 -> 정지
127+ continue
128+ dist = abs (mi - ci ) + abs (mj - cj ) # 현재 거리
129+ for di ,dj in dirs :
130+ ni ,nj = ci + di ,cj + dj # w 의 다음 이동 공간
131+ #범위내 메듀사 시야 아니고, 현재 거리보다 더 줄어드는 방향 (상하좌우 우선순위로 이동)
132+ if 0 <= ni < N and 0 <= nj < N and v [ni ][nj ]!= 1 and dist > abs (mi - ni )+ abs (mj - nj ):
133+ if (ni ,nj ) == (mi ,mj ): # 공격 -> 죽음
134+ attk += 1
135+ men .pop (idx )
136+ else :
137+ men [idx ] = [ni ,nj ]
138+ move += 1
139+ break
140+ return move , attk
141+
142+ ###############
143+ # main FLOW
144+ ###############
145+
146+
147+ # 0. 입력
148+ # 마을 크기 M , 전산수 N / 메듀사 위치정보s , 공원 위치 정보 e / M명 전사 좌표 N/ 개의 도로 정보
149+ N , M = map (int , input ().split ())
150+ si , sj , ei , ej = map (int , input ().split ())
151+ tlist = list (map (int , input ().split ()))
152+
153+ # 전사 좌표
154+ men = []
155+ for i in range (0 , M * 2 , 2 ) :
156+ men .append ([tlist [i ], tlist [i + 1 ]])
157+ # 필드 정보
158+ arr = [list (map (int , input ().split ())) for _ in range (N )]
159+
160+
161+
162+ # [0] BFS 로 메듀사 최단경로 : 도로 따라 공원까지 - 상하좌우
163+
164+ route = find_route (si ,sj ,ei ,ej )
165+
166+
167+
168+ if route == - 1 : # 길이 없는 경우
169+ print (- 1 )
170+ else :
171+ for mi ,mj in route : # 각 time = idx 별 메듀사 위치
172+ move_cnt , attk_cnt = 0 , 0
173+ # [1]메듀사의 이동 : 지정된 최단거리로 한칸 이동 (전사와 만날 경우 , 전사 삭제)
174+
175+ for i in range (len (men )- 1 ,- 1 ,- 1 ) : # 역순 탐색
176+ if men [i ] == [mi ,mj ] :
177+ men .pop (i )
178+
179+ #[2] 메듀사 시선 : 상하좌우 방향중 "가장 많이 stone 되는 방향" 선택
180+ # v[] : 메듀사의 시선 명시해서 이동시 참조(메듀사시선 =1 , 전사에게 가려진 곳 ==2 ,빈땅 ==0)
181+ # mar[][] : 지도에 있는 현재 전사 수 (및 위치) 표시(중복 존재 가능)
182+ marr = [[0 ]* N for _ in range (N )]
183+ for ti , tj in men :
184+ marr [ti ][tj ] += 1
185+
186+
187+ max_stone = - 1 # 4 방위 중 max stoning 가능한 개수
188+ v = [] #현 필드내 메듀사 시선으로 생기는 영억 속성 설정
189+
190+ # 4방위 바교
191+ for dr in (0 ,4 ,6 ,2 ) : # 상하좌우 순서대로 처리
192+ tv , tstone = make_stone (marr , mi , mj , dr )
193+ # 최대값 갱신 - max_stone 개수 & 시선 영역 속성 설정
194+ if max_stone < tstone :
195+ max_stone = tstone
196+ v = tv
197+
198+
199+
200+
201+ #[3] 전사의 이동 (한 칸씩 두번) : 메듀사 있는 경우 공격
202+ # 메듀사와 가까워지는 방향으로 접근
203+ move_cnt , attk_cnt = move_men (v ,mi ,mj )
204+
205+ print (move_cnt , max_stone , attk_cnt )
206+ print (0 )
0 commit comments