[ν”„λ‘œκ·Έλž˜λ¨ΈμŠ€ / Java] - 완전범죄

πŸ”— 문제 링크

완전범죄
μ½”λ”©ν…ŒμŠ€νŠΈ μ—°μŠ΅ - 완전범죄 λ¬Έμ œμž…λ‹ˆλ‹€.
school.programmers.co.kr

πŸ’‘ 문제 νŒŒμ•…

  • A와 B 두 λͺ…이 info.length 개의 물건을 ν•˜λ‚˜μ”©, μˆœμ„œλŒ€λ‘œ λ‘˜ 쀑 ν•œ λͺ…이 ν›”μΉœλ‹€. (λ¬Όκ±΄λ§ˆλ‹€ ν›”μΉ˜λŠ” μ‚¬λžŒμ„ μ •ν•΄μ•Ό 함)
  • info[i] = [a, b] λŠ” i 번째 물건을 Aκ°€ ν›”μΉ˜λ©΄ A의 흔적이 a 만큼, Bκ°€ ν›”μΉ˜λ©΄ B의 흔적이 b 만큼 λŠ˜μ–΄λ‚œλ‹€λŠ” λœ»μ΄λ‹€.
  • A의 흔적은 n 미만, B의 흔적은 m 미만으둜 μœ μ§€ν•΄μ•Ό μž‘νžˆμ§€ μ•ŠλŠ”λ‹€.
  • λͺ¨λ“  물건을 ν›”μΉ˜λ©΄μ„œ λ‘˜ λ‹€ μž‘νžˆμ§€ μ•Šμ„ 수 μžˆλŠ” 경우 쀑, A의 μ΅œμ’… 흔적이 μ΅œμ†Œκ°€ λ˜λŠ” 값을 κ΅¬ν•œλ‹€. 그런 λΆ„λ°°κ°€ λΆˆκ°€λŠ₯ν•˜λ©΄ -1을 λ°˜ν™˜ν•œλ‹€.

πŸ—οΈ μ ‘κ·Ό 방법

  • i 번째 λ¬Όκ±΄κΉŒμ§€ μ²˜λ¦¬ν–ˆμ„ λ•Œ "A의 흔적이 μ •ν™•νžˆ a, B의 흔적이 μ •ν™•νžˆ bκ°€ λ˜λŠ” λΆ„λ°°κ°€ κ°€λŠ₯ν•œκ°€?"λ₯Ό μƒνƒœλ‘œ κ°–λŠ” dp[len + 1][n][m] λΆˆλ¦¬μ–Έ 배열을 μ‚¬μš©ν•œλ‹€.
  • dp[0][0][0] = true μ—μ„œ μ‹œμž‘ν•΄μ„œ, 물건을 ν•˜λ‚˜μ”© μ²˜λ¦¬ν•  λ•Œλ§ˆλ‹€ 두 κ°€μ§€ 선택을 λͺ¨λ‘ μ „μ΄μ‹œν‚¨λ‹€.
    • Aκ°€ ν›”μΉ˜λŠ” 경우: traceA + a < n 이면 dp[i + 1][traceA + a][traceB] = true
    • Bκ°€ ν›”μΉ˜λŠ” 경우: traceB + b < m 이면 dp[i + 1][traceA][traceB + b] = true
    • 흔적이 μž„κ³„κ°’(n, m) 이상이 λ˜λŠ” μ „μ΄λŠ” μž‘νžˆλŠ” κ²½μš°μ΄λ―€λ‘œ μ•„μ˜ˆ λ§Œλ“€μ§€ μ•ŠλŠ”λ‹€.
  • λͺ¨λ“  물건(len)을 μ²˜λ¦¬ν•œ λ’€, dp[len][traceA][traceB] κ°€ true 인 μƒνƒœλ“€ 쀑 traceA κ°€ κ°€μž₯ μž‘μ€ 값을 μ°ΎλŠ”λ‹€.
    • traceA λ₯Ό 0λΆ€ν„° μˆœμ„œλŒ€λ‘œ νƒμƒ‰ν•˜λ―€λ‘œ, 처음으둜 true λ₯Ό λ§Œλ‚˜λŠ” 값이 κ³§ μ΅œμ†Ÿκ°’μ΄ λ˜μ–΄ λ°”λ‘œ λ°˜ν™˜ν•  수 μžˆλ‹€.
  • λκΉŒμ§€ true 인 μƒνƒœκ°€ ν•˜λ‚˜λ„ μ—†λ‹€λ©΄ λ‘˜ λ‹€ μ•ˆ 작히게 λͺ¨λ“  물건을 λΆ„λ°°ν•  방법이 μ—†λ‹€λŠ” λœ»μ΄λ―€λ‘œ -1을 λ°˜ν™˜ν•œλ‹€.
// Aκ°€ ν›”μΉ¨
if (traceA + a < n) {
    dp[i + 1][traceA + a][traceB] = true;
}

// Bκ°€ ν›”μΉ¨
if (traceB + b < m) {
    dp[i + 1][traceA][traceB + b] = true;
}

🧩 μ½”λ“œ κ΅¬ν˜„

class Solution {
    public int solution(int[][] info, int n, int m) {
        int len = info.length;

        // i개의 물건을 μ²˜λ¦¬ν–ˆμ„ λ•Œ, A의 흔적이 a, B의 흔적이 bκ°€ λ˜λŠ” κ²½μš°κ°€ μ‘΄μž¬ν•¨?
        boolean[][][] dp = new boolean[len + 1][n][m]; // i, a, b

        dp[0][0][0] = true;

        for (int i = 0; i < len; i++) {
            int a = info[i][0];
            int b = info[i][1];

            for (int traceA = 0; traceA < n; ++traceA) {
                for (int traceB = 0; traceB < m; ++traceB) {
                    if (!dp[i][traceA][traceB]) continue;

                    // Aκ°€ ν›”μΉ¨
                    if (traceA + a < n) {
                        dp[i + 1][traceA + a][traceB] = true;
                    }

                    // Bκ°€ ν›”μΉ¨
                    if (traceB + b < m) {
                        dp[i + 1][traceA][traceB + b] = true;
                    }
                }
            }
        }

        for (int traceA = 0; traceA < n; ++traceA) {
            for (int traceB = 0; traceB < m; ++traceB) {
                if (dp[len][traceA][traceB]) {
                    return traceA;
                }
            }
        }
        return -1;
    }
}