728x90
시간 제한 1초, 메모리 제한 512MB
# 조건
- 캐슬 디펜스는 성을 향해 몰려오는 적을 잡는 턴 방식의 게임이다.
- 게임이 진행되는 곳은 크기가 N×M인 격자판으로 나타낼 수 있다.
- 격자판은 1×1 크기의 칸으로 나누어져 있고, 각 칸에 포함된 적의 수는 최대 하나이다.
- 격자판의 N번행의 바로 아래(N+1번 행)의 모든 칸에는 성이 있다.
- 성을 적에게서 지키기 위해 궁수 3명을 배치하려고 한다.
- 궁수는 성이 있는 칸에 배치할 수 있고, 하나의 칸에는 최대 1명의 궁수만 있을 수 있다.
- 각각의 턴마다 궁수는 적 하나를 공격할 수 있고, 모든 궁수는 동시에 공격한다.
- 궁수가 공격하는 적은 거리가 D이하인 적 중에서 가장 가까운 적이고, 그러한 적이 여럿일 경우에는 가장 왼쪽에 있는 적을 공격한다.
- 같은 적이 여러 궁수에게 공격당할 수 있다.
- 공격받은 적은 게임에서 제외된다.
- 궁수의 공격이 끝나면, 적이 이동한다.
- 적은 아래로 한 칸 이동하며, 성이 있는 칸으로 이동한 경우에는 게임에서 제외된다.
- 모든 적이 격자판에서 제외되면 게임이 끝난다.
- 게임 설명에서 보다시피 궁수를 배치한 이후의 게임 진행은 정해져있다.
- 따라서, 이 게임은 궁수의 위치가 중요하다.
- 격자판의 상태가 주어졌을 때, 궁수의 공격으로 제거할 수 있는 적의 최대 수를 계산해보자.
- 격자판의 두 위치 (r1, c1), (r2, c2)의 거리는 |r1-r2| + |c1-c2|이다.
입력
- 첫째 줄에 격자판 행의 수 N, 열의 수 M, 궁수의 공격 거리 제한 D가 주어진다.
- 둘째 줄부터 N개의 줄에는 격자판의 상태가 주어진다.
- 0은 빈 칸, 1은 적이 있는 칸이다.
출력
- 첫째 줄에 궁수의 공격으로 제거할 수 있는 적의 최대 수를 출력한다.
# 제한
- 3<=N, M<=15
- 1<=D<=10
# 접근 방법
- 구현, 시뮬레이션 문제이다.
- 따라서 우선 조건을 나눠주면서 아래 키 포인트들을 정리해봤다.
- 최단 거리의 적을 찾는데 같은 거리라면 가장 왼쪽의 적을 공격
- 같은 적이 여러 궁수에게 공격 받을 수 있음
- 적은 공격이 끝난 후 아래로 한 칸 이동 후, 성이라면 제외
- 궁수의 위치를 배치해주기 위하여 itertools의 combination을 사용해주었다.
- 0~M-1까지의 숫자를 3개씩 뽑아주면 된다.
- 또한 궁수의 배치에 따라 적을 초기화 해주어야 하므로 각 조합을 탐색 시작할 때 origin 배열을 enemy로 깊은 복사해주었다.
- find 함수
- 각 궁수를 순회하며 모든 적을 탐색한다.
- 이 때, 가장 좌측 먼저 탐색하도록 enemy를 열을 기준으로 오름 차순 정렬해주었다.
- 만약 멘허튼 거리가 현재 기록되어있는 min_dist보다 작다면, 해당 적을 갱신하고 위치를 기록해준다.
- 여러 궁수가 한 적을 공격할 수 있기에 죽이는 적은 set()에 저장해주었다.
- 만약 죽일 수 있는 적이 있다면 kill_enemy함수를 실행해준다.
- kill_enemy
- 위치를 순회하며 enemy에서 제거해준다.
- 또한, 현재 궁수로 죽인 cnt를 +1 해준다.
- move_enemy
- 궁수의 공격이 끝났으므로 적을 움직여준다.
- enemy를 순회하며 한 칸 아래가 성 == N이라면 temp에 몇 번째 적인지 기록해준다.
- 아니라면 enemy값을 갱신해준다.
- temp가 존재한다면 내림 차순정렬을 하고 해당 되는 인덱스의 적을 제외시켜 준다.
import sys
sys.stdin = open('input.txt')
input = sys.stdin.readline
from itertools import combinations
from copy import deepcopy
def find_enemy(loc):
global D
find = set()
for i, j in loc:
flag = False
min_dist = float('inf')
kill = (0, 0)
for ei, ej in enemy:
dist = abs(i - ei) + abs(j - ej)
if dist <= D and dist < min_dist:
min_dist = dist
kill = (ei, ej)
flag = True
if flag:
find.add(kill)
if find:
kill_enemy(find)
def kill_enemy(find):
global cnt_kill
for fi, fj in find:
enemy.remove([fi, fj])
cnt_kill += 1
def move_enemy():
temp = []
for idx, val in enumerate(enemy):
if val[0] + 1 == N:
temp.append(idx)
else:
enemy[idx] = [val[0]+1, val[1]]
if temp:
temp.sort(reverse=True)
for i in temp:
enemy.pop(i)
N, M, D = map(int, input().split())
arr = [list(map(int, input().split())) for _ in range(N)]
origin = []
for i in range(N):
for j in range(M):
if arr[i][j] == 1:
origin.append([i, j])
result = 0
for comb in combinations(range(M), 3):
enemy = deepcopy(origin)
archer = []
cnt_kill = 0
for c in comb:
archer.append([N, c])
while enemy:
enemy.sort(key=lambda x:x[1])
find_enemy(archer)
move_enemy()
result = max(cnt_kill, result)
print(result)
- 다만, 삼성 기출인 만큼 itertools를 사용 못한다는 말도 있으니 다음에는 조합을 구현하는 것까지 해야겠다..!
728x90
'ALGORITHM > Brute Force' 카테고리의 다른 글
[백준 21610번] 파이썬 - 마법사 상어와 비바라기 (0) | 2024.03.30 |
---|---|
[백준 20002번] 파이썬 - 사과나무 (0) | 2024.02.22 |
[백준 19699번] 파이썬 - 소-난다! (1) | 2023.10.11 |
[백준 5568번] 파이썬 - 카드 놓기 (0) | 2023.09.13 |
[백준 2422번] 파이썬 - 한윤정이 이탈리아에 가서 아이스크림을 사먹는데 (3) | 2023.08.27 |