1006 : 습격자 초라기#
시간제한 |
메모리제한 |
정답비율 |
---|---|---|
2초 |
512MB |
19.8% |
문제#
초라기는 한국의 비밀국방기지(원타곤)를 습격하라는 임무를 받은 특급요원이다. 원타곤의 건물은 도넛 형태이며, 초라기는 효율적인 타격 포인트를 정하기 위해 구역을 아래와 같이 두 개의 원 모양으로 나누었다.
초라기는 각각 W명으로 구성된 특수소대를 다수 출동시켜 모든 구역에 침투시킬 예정이며, 각 구역 별로 적이 몇 명씩 배치되어 있는지는 초라기가 모두 알고 있다. 특수소대를 아래 조건에 따라 침투 시킬 수 있다.
한 특수소대는 침투한 구역 외에, 인접한 한 구역 더 침투할 수 있다. (같은 경계를 공유하고 있으면 인접 하다고 한다. 위 그림에서 1구역은 2, 8, 9 구역과 서로 인접한 상태다.) 즉, 한 특수소대는 한 개 혹은 두 개의 구역을 커버할 수 있다.
특수소대끼리는 아군인지 적인지 구분을 못 하기 때문에, 각 구역은 하나의 소대로만 커버해야 한다.
한 특수소대가 커버하는 구역의 적들의 합은 특수소대원 수 W 보다 작거나 같아야 한다.
이때 초라기는 원타곤의 모든 구역을 커버하기 위해 침투 시켜야 할 특수 소대의 최소 개수를 알고 싶어 한다.
입력
첫째 줄에 테스트 케이스의 개수 T가 주어진다. 각 테스트 케이스는 다음과 같이 구성되어있다.
첫째 줄에는 (구역의 개수)/2 값 N과 특수 소대원의 수 W가 주어진다. (1 ≤ N ≤ 10000, 1 ≤ W ≤ 10000).
둘째 줄에는 1~N번째 구역에 배치된 적의 수가 주어지고, 셋째 줄에는 N+1 ~ 2N번째 구역에 배치된 적의 수가 공백으로 구분되어 주어진다. (1 ≤ 각 구역에 배치된 최대 적의 수 ≤ 10000) 단, 한 구역에서 특수 소대원의 수보다 많은 적이 배치된 구역은 존재하지 않는다. (따라서, 각 구역에 배치된 최대 적의 수 ≤ W)
출력
각 테스트케이스에 대해서 한 줄에 하나씩 원타곤의 모든 구역을 커버하기 위해 침투 시켜야 할 특수 소대의 최소 개수를 출력하시오.
think#
dp문제이니깐 문제를 작은 것으로 나누는 최적의 원리
랑 memorization을 이용해야할 것이다.
점화식을 세워보고
이전의 결과물이 뒤에 활용될 수 있으려면 최적의 원리. 그 순간의 최적이 뒤의 최적이 되어야한다.
그리고 이에 대해서 저장을 해서 계산효율성을 높여야한다.
여기서 최적이 되어야할 부분은 무엇일까?
python#
import sys, os
problem_num = "1006"
path = os.getcwd() + f"\\txt\\{problem_num}" + ".txt"
sys.stdin = open(path, "r")
input = sys.stdin.readline
class PentagonAttack:
def __init__(self, n, w, enemies):
self.n = n
self.w = w
self.enemies = enemies
self.dp = [[-1] * (2 * w * n + 1) for _ in range(n + 1)]
def solve(self):
result = self.min_special_forces(self.n, 0)
return result
def min_special_forces(self, remaining_sections, current_enemy_sum):
if remaining_sections == 0:
return 0
if self.dp[remaining_sections][current_enemy_sum] != -1:
return self.dp[remaining_sections][current_enemy_sum]
# 특수 소대원이 0명일 때는 침투를 하지 않음
min_special_forces_needed = self.min_special_forces(
remaining_sections - 1, current_enemy_sum
)
# 현재 구역의 최대 적 수와 특수 소대원 수 중 작은 값을 선택
max_enemies = min(self.w, self.enemies[remaining_sections - 1]) + 1
# 특수 소대원을 배치하거나 배치하지 않는 경우 중 최소값 선택
for i in range(max_enemies):
min_special_forces_needed = min(
min_special_forces_needed,
self.min_special_forces(remaining_sections - 1, current_enemy_sum + i)
+ (i > 0),
)
self.dp[remaining_sections][current_enemy_sum] = min_special_forces_needed
return min_special_forces_needed
# 테스트 케이스 입력 및 실행
T = int(input())
for _ in range(T):
N, W = map(int, input().split())
enemies1 = list(map(int, input().split()))
enemies2 = list(map(int, input().split()))
# 두 구역의 적을 합쳐서 하나의 리스트로 만듦
enemies = enemies1 + enemies2
# 클래스 생성 및 실행
pentagon_attack = PentagonAttack(N, W, enemies)
result = pentagon_attack.solve()
# 결과 출력
print(result)
0