geeksforgeeks.org

Box Stacking / geeksforgeeks.org

건이두 2019. 12. 23. 16:46
728x90

Dydnamic Programming의 대표적인 문제 중의 하나입니다. Box Stacking
geeksforgeeks.org 사이트의 Box Stacking문제를 풀어 보겠습니다.

문제 링크 → Box Stacking

자바 소스를 찾으 시는 분은 여기→Github link

import java.util.Arrays;
import java.util.Scanner;

// https://practice.geeksforgeeks.org/problems/box-stacking/1
// 문제 설명이 부족한 부분이 있습니다.
// 박스를 돌릴 수 있다고만 설명 되어 있지,
// 돌린 박스는 중복해서 사용할 수 있는 것으로 풀어야 합니다.
// 즉, 1, 2, 3 (h, w, l) 인 박스가 있으면,
// 실제로 박스 쌓을 때는 3개의 박스가 있는 것으로 풀어야 합니다.
// 1, 2, 3 / 3, 1, 2 / 2, 3, 1 이렇게 3개의 박스를 서로 다른 박스로 보고, 쌓을 수 있는 것으로 풀어야 합니다.
public class Geeks {
    static class Box implements Comparable<Box>{
        public int mh, mw, ml;
        public int mArea;
        public Box(int h, int w, int l) {
            mh = h;
            mw = w;
            ml = l;
            mArea = mh * mw;
        }

        // 내 위에, b 박스를 올려 놓을 수 있는가?
        // true 올려 놓을 수 있음
        // false 올려 놓을 수 없음
        public boolean IsAbleToStackAbove(Box b) {
            if(b.mh < mh && b.mw < mw)
                return true;

            return false;
        }

        @Override
        public int compareTo(Box o) {
            return o.mArea - mArea;
        }
    }

    public static int maxHeight(int height[], int width[], int length[], int n) {
        int r = 0;

        Box[] boxes = new Box[n*3];
        int[] msh = new int[n*3];

        // 문제에 잘 설명이 되어 있지를 않아서, 저도 다른 사람의 풀이를 보고 알게 되었습니다.
        // 박스는 돌릴 수 있기 때문에 3개 존재 합니다.
        // 심지어 박스를 돌려서, 돌리기 전의 박스와, 돌린 후의 박스에도 올릴 수 있습니다.
        // 이러면, 좀 문제가 이상해지는 것 같기는 한대....
        // 뭐 그렇게 되어 있네요.
        for(int i=0; i<n; ++i) {
            int h = height[i];
            int w = width[i];
            int l = length[i];

            boxes[i*3+0] = new Box(Math.max(h, w), Math.min(h, w), l);
            boxes[i*3+1] = new Box(Math.max(l, h), Math.min(l, h), w);
            boxes[i*3+2] = new Box(Math.max(w, l), Math.min(w, l), h);
        }

        // 박스 스택 문제에서 중요한 부분입니다.
        // 박스를 크기 순으로 내림 차순으로 정렬합니다.
        Arrays.sort(boxes);
        // 그러면 1번 박스위에 2번 박스가 올라 갈 수 있다고 할 때,
        // 2번 박스의 msh(maximum stack height)는 1번박스 ml + 2번 박스 ml 이 되구요.
        // 어떤 n 번째 있는 박스가  n-1 번째 박스위에 올라 갈 수 있으면
        // msh[n] = n번째 박스.l + msh[n-1] 이 됩니다.
        // 이렇게 풀기 위해서, 박스를 면적의 내림차순으로 정렬해야 합니다.

        for(int i=0; i<n*3; ++i)
            msh[i] = boxes[i].ml;

        for(int i=0; i<n*3; ++i) {
            for(int j=0; j<i; ++j) {
                if(boxes[j].IsAbleToStackAbove(boxes[i])){
                    int tmp = msh[j] + boxes[i].ml;
                    msh[i] = Math.max(msh[i], tmp);
                }
            }
        }

        // 1 부터 시작해도 됩니다.
        // 박스가 1개만 있다고 해도, 앞에서 말씀드린 것 처럼
        // 돌리는 것을 가만해서, 박스가 3개 존재 합니다.
        // 문제의 입력값에 1<=N 으로 되어 있습니다.
        r = msh[0];
        for(int i=1; i<n*3; ++i)
            r = Math.max(r, msh[i]);

        return r;
    }

    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        int T = sc.nextInt();

        for(int t=0; t<T; ++t) {
            int N = sc.nextInt();
            int h[] = new int[N];
            int w[] = new int[N];
            int l[] = new int[N];

            for(int n=0; n<N; ++n) {
                h[n] = sc.nextInt();
                w[n] = sc.nextInt();
                l[n] = sc.nextInt();
            }

            int r = maxHeight(h, w, l, N);
            System.out.println(r);
        }
    }
}
728x90