새소식

PS/백준

[백준/1006] 습격자 초라기 (Python)

  • -

Problem :

 

Difficulty : Platinum 3

 

Status : Solved

 

Time : 00:55:53

 


 

문제 설명

 

더보기

 

초라기는 한국의 비밀국방기지(원타곤)를 습격하라는 임무를 받은 특급요원이다. 원타곤의 건물은 도넛 형태이며, 초라기는 효율적인 타격 포인트를 정하기 위해 구역을 아래와 같이 두 개의 원 모양으로 나누었다. (그림의 숫자는 각 구역의 번호이다.)

초라기는 각각 W명으로 구성된 특수소대를 다수 출동시켜 모든 구역에 침투시킬 예정이며, 각 구역 별로 적이 몇 명씩 배치되어 있는지는 초라기가 모두 알고 있다. 특수소대를 아래 조건에 따라 침투 시킬 수 있다.

  • 한 특수소대는 침투한 구역 외에, 인접한 한 구역 더 침투할 수 있다. (같은 경계를 공유하고 있으면 인접 하다고 한다. 위 그림에서 1구역은 2, 8, 9 구역과 서로 인접한 상태다.) 즉, 한 특수소대는 한 개 혹은 두 개의 구역을 커버할 수 있다.
  • 특수소대끼리는 아군인지 적인지 구분을 못 하기 때문에, 각 구역은 하나의 소대로만 커버해야 한다.
  • 한 특수소대가 커버하는 구역의 적들의 합은 특수소대원 수 W 보다 작거나 같아야 한다.

이때 초라기는 원타곤의 모든 구역을 커버하기 위해 침투 시켜야 할 특수 소대의 최소 개수를 알고 싶어 한다.

 

 

입력 및 출력

 

더보기

입력

 

첫째 줄에 테스트 케이스의 개수 T가 주어진다. 각 테스트 케이스는 다음과 같이 구성되어있다.

첫째 줄에는 (구역의 개수)/2 값 N과 특수 소대원의 수 W가 주어진다. (1 ≤ N ≤ 10000, 1 ≤ W ≤ 10000).

둘째 줄에는 1~N번째 구역에 배치된 적의 수가 주어지고, 셋째 줄에는 N+1 ~ 2N번째 구역에 배치된 적의 수가 공백으로 구분되어 주어진다. (1 ≤ 각 구역에 배치된 최대 적의 수 ≤ 10000) 단, 한 구역에서 특수 소대원의 수보다 많은 적이 배치된 구역은 존재하지 않는다. (따라서, 각 구역에 배치된 최대 적의 수 ≤ W)

 

출력

 

각 테스트케이스에 대해서 한 줄에 하나씩 원타곤의 모든 구역을 커버하기 위해 침투 시켜야 할 특수 소대의 최소 개수를 출력하시오.

 

입력 예시

 

1
8 100
70 60 55 43 57 60 44 50
58 40 47 90 45 52 80 40

 

출력 예시

 

11

 

 


 

풀이

 

드디어 도전한 킹격자 갓라기 문제... 충분히 대비했다고 생각했어도 틀리는 건 어쩔 수 없었고, 테스트케이스의 도움을 받아 탈출할 수 있었다. 감사합니다 수많은 선배님들...!!

 

핵심은 DP를 어떻게 해결할 것이냐이다. 우선 DP[i][j]를 i번째 행의 j번째 열까지 배치한 최솟값이라고 생각하자. j = 0, 1일 경우 윗열, 아랫열 하나만을 배치한 경우이고, j = 2인 경우 윗열 및 아랫열 모두 배치가 완료된 케이스라고 정의하자.

 

초기화부터 생각해보면, 1번째와 N번째가 아예 이어지지 않는 경우, 1번째 원소 하나만이 N번째와 이어지는 경우 2가지, 둘 다 이어지는 경우 1가지로 총 4가지이다. 이 4가지 경우 중 전자를 제외한 나머지 경우 인접한 두 적들의 합이 W보다 작거나 같을 때만을 고려하도록 한다. 

 

또한 이 4가지는 초기화할 때, 그리고 마지막에 참조하는 DP값이 각각 다르다. 이를테면 아예 이어지지 않는 경우 DP[0][2] = 1 또는 2가 될 수 있다. 하지만 1번째 원소 하나 이상이 이어진 경우 이어진 부분의 반대 열에 대한 초기화가 불가능하다. 이를테면, 0번 열이 이어졌다면 DP[0][1]은 존재할 수 없다. 이미 0번 열이 사용되었으므로 1번 열만 사용된 경우 자체를 고려할 수 없기 때문이다. 또한 마지막에 참조하는 값 역시 사용된 경우를 고려해야 한다. 위 네 가지 경우에 대해 각각 DP[N-1][2], DP[N-1][1]. DP[N-1][0], DP[N-2][2]로 대응된다. 

 

다음은 DP의 업데이트이다. 

  • j = 0, 1인 경우, 만약 같은 열의 이전에 인접한 값과의 합이 W 이하라면 둘을 합치는 경우를 고려할 수 있다. 즉 DP[i-1][1-j] + 1 (반대쪽 열이 사용된 경우)로 업데이트할 수 있다. 혹은 DP[i-1][2] + 1 인 경우(즉 (i, j)하나만을 고려하는 경우) 역시 가능하다.
  • j = 2인 경우, 기본적으로는 (j = 0, 1인 경우 + 1) 을 고려할 수 있다. 혹은 두 열 모두 이전 행의 값과 합칠 수 있는 경우, DP[i-2][2] + 2 값으로도 업데이트할 수 있다.

마지막으로, N <= 2인 엣지 케이스에는 주의해서 적용되어야 한다. 회전해도 같은 경우 등이 있을 수 있다.

 

풀이 코드

import sys
input = sys.stdin.readline
MAX = float('inf')

def solve() :
  global N, W, enemy_list
  N, W = map(int, input().split())
  enemy_list = [list(map(int, input().split())) for _ in range(2)]

  flg = 0
  result = MAX
  result = min(result, cal_dp(0))
  for i in range(2) :
    if N > 1 and enemy_list[i][0] + enemy_list[i][-1] <= W :
      result = min(result, cal_dp(i+1))
      flg += 1

  if N > 2 and flg == 2 :
    result = min(result, cal_dp(3))
  print(result)

def dp_init(dp, mode = 0) :
  if mode not in [1, 3] :
    dp[0][1] = 1
  if mode not in [2, 3] :
    dp[0][0] = 1
  if mode == 0 and enemy_list[0][0] + enemy_list[1][0] <= W :
    dp[0][2] = 1
  else :
    dp[0][2] = 2

def dp_result(dp, mode = 0) :
  if mode == 0 :
    return dp[-1][2]
  elif mode in [1, 2] :
    return dp[-1][2-mode]
  else :
    return dp[-2][2]

def cal_dp(mode = 0) :
  dp = [[MAX]*3 for _ in range(N)]
  dp_init(dp, mode)

  for i in range(1, N) :
    flg = 0
    for j in range(2) :
      if enemy_list[j][i-1] + enemy_list[j][i] <= W :
        flg += 1
        dp[i][j] = min(dp[i][j], dp[i-1][1-j]+1)
      dp[i][j] = min(dp[i][j], dp[i-1][2]+1)
      dp[i][2] = min(dp[i][2], dp[i][j]+1)
    if enemy_list[0][i] + enemy_list[1][i] <= W :
      dp[i][2] = min(dp[i][2], dp[i-1][2]+1)
    if flg == 2 :
      if i > 1 :
        dp[i][2] = min(dp[i][2], dp[i-2][2]+2)
      elif mode == 0 :
        dp[i][2] = min(dp[i][2], 2)
  return dp_result(dp, mode)

for _ in range(int(input())) :
  solve()

풀이 완료!

'PS > 백준' 카테고리의 다른 글

[백준/1201] NMK (Python)  (0) 2023.11.03
[백준/1507] 궁금한 민호 (Python)  (0) 2023.11.02
[백준/16287] Parcel (Python)  (1) 2023.10.31
[백준/1634] 완전 이진트리 (Python)  (1) 2023.10.30
[백준/1328] 고층 빌딩 (Python)  (0) 2023.10.29
Contents

포스팅 주소를 복사했습니다

이 글이 도움이 되었다면 공감 부탁드립니다.