2 분 소요

1. 문제

https://www.acmicpc.net/problem/2655

  • DP, LIS 문제
// 문제
밑면이 정사각형인 직육면체 벽돌들을 사용하여 탑을 쌓고자 한다.
탑은 벽돌을  개씩 아래에서 위로 쌓으면서 만들어 간다.
아래의 조건을 만족하면서 가장 높은 탑을 쌓을  있는 프로그램을 작성하시오.

벽돌은 회전시킬  없다.
, 옆면을 밑면으로 사용할  없다.
밑면의 넓이가 같은 벽돌은 없으며, 또한 무게가 같은 벽돌도 없다.
벽돌들의 높이는 같을 수도 있다.
탑을 쌓을  밑면이 좁은 벽돌 위에 밑면이 넓은 벽돌은 놓을  없다.
무게가 무거운 벽돌을 무게가 가벼운 벽돌 위에 놓을  없다.

// 입력
첫째 줄에는 입력될 벽돌의 수가 주어진다.
입력으로 주어지는 벽돌의 수는 최대 100개이다.
둘째 줄부터는  줄에  개의 벽돌에 관한 정보인 벽돌 밑면의 넓이,
벽돌의 높이 그리고 무게가 차례대로 양의 정수로 주어진다.
 벽돌은 입력되는 순서대로 1부터 연속적인 번호를 가진다.
벽돌의 넓이, 높이 무게는 10,000보다 작거나 같은 자연수이다.

// 출력
탑을 쌓을  사용된 벽돌의 수를 빈칸없이 출력하고,
 번째 줄부터는 탑의 가장  벽돌부터 가장 아래 벽돌까지
차례로  줄에 하나씩 벽돌 번호를 빈칸없이 출력한다.

// 예제 입력 1
5
25 3 4
4 4 6
9 2 3
16 2 5
1 5 2

// 예제 출력 1
3
5
3
1


2. 핵심 아이디어

  • 가장 긴 증가하는 부분 수열 문제의 심화 변형 문제
  • 벽돌의 수가 N개일 때, 시간 복잡도 O(N^2)으로 해결할 수 있음
  • 벽돌의 번호를 출력해야 한다는 점에서, 계산된 테이블을 역추적할 수 있어야 함
  • 가장 먼저 벽돌을 무게 기준으로 정렬
  • D(i) = 인덱스가 i인 벽돌을 가장 아래에 두었을 때의 최대 높이
  • 각 벽돌에 대해서 확인하며 D(i)를 갱신
  • 모든 0 <= j < i 에 대하여, D(i) = max(D(i), D(j) + height(i) if area(i) > area(j))

baekjoon-2655


3. Python 문제풀이

import sys
input = sys.stdin.readline

n = int(input())
arr = []

arr.append((0, 0, 0, 0))

for i in range(1, n + 1) :
  area, height, weight = map(int, input().split())
  arr.append((i, area, height, weight))

# 무게 기준 정렬
arr.sort(key = lambda data: data[3])

dp = [0] * (n + 1)

for i in range(1, n + 1) :
  for j in range(0, i) :
    if arr[i][1] > arr[j][1] :
      dp[i] = max(dp[i], dp[j] + arr[i][2])

max_value = max(dp)
index = n
result = []

while index != 0 :
  if max_value == dp[index] :
    result.append(arr[index][0])
    max_value -= arr[index][2]
  index -= 1

result.reverse()
print(len(result))
[print(i) for i in result]


4. Java 문제풀이

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Comparator;
import java.util.StringTokenizer;

class Main {
  public static void main(String[] args) throws IOException {
    BufferedReader br = new BufferedReader(new InputStreamReader(System.in));

    int n = Integer.parseInt(br.readLine());
    int[][] arr = new int[n + 1][4];

    for (int i=1; i<n+1; i++) {
      StringTokenizer st = new StringTokenizer(br.readLine());
      arr[i][0] = i;
      arr[i][1] = Integer.parseInt(st.nextToken());
      arr[i][2] = Integer.parseInt(st.nextToken());
      arr[i][3] = Integer.parseInt(st.nextToken());
    }

    Arrays.sort(arr, new Comparator<int[]>() {
      @Override
      public int compare(int[] o1, int[] o2) {
        return Integer.compare(o1[3], o2[3]);
      }
    });

    int[] dp = new int[n + 1];

    for (int i=1; i<n+1; i++) {
      for (int j=0; j<i; j++) {
        if (arr[i][1] > arr[j][1]) {
          dp[i] = Math.max(dp[i], dp[j] + arr[i][2]);
        }
      }
    }

    int max_value = 0;
    for (int i : dp) {
      max_value = Math.max(i, max_value);
    }

    int index = n;
    ArrayList<Integer> result = new ArrayList<Integer>();

    while (index != 0) {
      if (max_value == dp[index]) {
        result.add(arr[index][0]);
        max_value -= arr[index][2];
      }
      index--;
    }
    System.out.println(result.size());

    for (int i=result.size()-1; i>=0; i--) {
      System.out.println(result.get(i));
    }
  }
}

댓글남기기