[c++] ν”„λ‘œκ·Έλž˜λ¨ΈμŠ€ :: λ„λ‘‘μ§ˆ

문제

문제 μ„€λͺ…

도둑이 μ–΄λŠ λ§ˆμ„μ„ ν„Έ κ³„νšμ„ ν•˜κ³  μžˆμŠ΅λ‹ˆλ‹€. 이 λ§ˆμ„μ˜ λͺ¨λ“  집듀은 μ•„λž˜ κ·Έλ¦Όκ³Ό 같이 λ™κ·Έλž—κ²Œ λ°°μΉ˜λ˜μ–΄ μžˆμŠ΅λ‹ˆλ‹€.

image.png

각 집듀은 μ„œλ‘œ μΈμ ‘ν•œ 집듀과 λ°©λ²”μž₯μΉ˜κ°€ μ—°κ²°λ˜μ–΄ 있기 λ•Œλ¬Έμ— μΈμ ‘ν•œ 두 집을 ν„Έλ©΄ 경보가 μšΈλ¦½λ‹ˆλ‹€.

각 집에 μžˆλŠ” 돈이 λ‹΄κΈ΄ λ°°μ—΄ moneyκ°€ μ£Όμ–΄μ§ˆ λ•Œ, 도둑이 ν›”μΉ  수 μžˆλŠ” 돈의 μ΅œλŒ“κ°’μ„ return ν•˜λ„λ‘ solution ν•¨μˆ˜λ₯Ό μž‘μ„±ν•˜μ„Έμš”.

 

μ œν•œμ‚¬ν•­

  • 이 λ§ˆμ„μ— μžˆλŠ” 집은 3개 이상 1,000,000개 μ΄ν•˜μž…λ‹ˆλ‹€.
  • money λ°°μ—΄μ˜ 각 μ›μ†ŒλŠ” 0 이상 1,000 μ΄ν•˜μΈ μ •μˆ˜μž…λ‹ˆλ‹€.

 

풀이

  • λ§Œμ•½ μ™„μ „νƒμƒ‰μœΌλ‘œ ν•˜κ³ μž ν–ˆλ‹€λ©΄?
    • λ°˜λ³΅μ„ index 0λΆ€ν„° n-1κΉŒμ§€ λŒλ©΄μ„œ ν•΄λ‹Ή μ§‘μ—μ„œ μ‹œμž‘ν•΄μ„œ λ‚˜νƒ€λ‚˜λŠ” μ΅œλŒ€μ˜ moneyλ₯Ό ꡬ할 수 있음
    • ν•˜μ§€λ§Œ index 2λ₯Ό κ³ λ₯Έλ‹€λ©΄, μ§‘μ˜ κ°œμˆ˜κ°€ 짝수일 λ•Œ index 0을 κ³ λ₯Ό 수 있고 ν™€μˆ˜μΌ λ•Œ index 1을 κ³ λ₯Ό 수 있음
      • 고둜 index 0κ³Ό 1만 κ³ λ €ν•˜λ©΄ 됨
  • DP
    • 3번째 <μž¬κ·€ν•¨μˆ˜> μ½”λ“œ
      • top-down λ°©μ‹μœΌλ‘œ ν•΄λ‹Ή indexμ—μ„œμ˜ maxMoney κ΅¬ν•΄μ„œ μ €μž₯
    • 점화식 풀이 μ½”λ“œ
      • DPλŠ” 배열을 μ΄μš©ν•œ 점화식 풀이λ₯Ό λ¨Όμ € 생각해보고 μ•ˆλ˜λ©΄ μž¬κ·€ν•¨μˆ˜λ‘œ 돌리자.
      • 1차원 λ°°μ—΄(arr)μ—μ„œ μ§‘μ˜ indexλ₯Ό λ°°μ—΄μ˜ index, 값을 μ΅œλŒ€ money둜 보자.
      • 1번째 top-down (λ°°μ—΄μœΌλ‘œ 봀을 λ•Œ, λ§ˆμ§€λ§‰ μš”μ†Œλ₯Ό κ΅¬ν•˜κΈ° μœ„ν•΄ 이전 μš”μ†Œλ₯Ό 이용) μ½”λ“œ
        • ν˜„μž¬ indexλ₯Ό i라 ν•  λ•Œ,
        • arr[i] = max(arr[i-2]+ money[i], arr[i-1])
      • 2번째 bottom-up (λ°°μ—΄μœΌλ‘œ 봀을 λ•Œ, 첫번째 μš”μ†Œλ₯Ό μ΄μš©ν•΄μ„œ λ§ˆμ§€λ§‰ μš”μ†Œλ“€μ„ 생성) μ½”λ“œ
        • arr[i+2] = max(arr[i+2], arr[i] + money[i+2])
        • arr[i+1] = max(arr[i+1], arr[i])

 

μ½”λ“œ

<점화식 top-down>

#include <string>
#include <vector>
#include <cstring>
#include <algorithm>

using namespace std;
int memo[1000001];
int memo2[1000001];

int solution(vector<int> money) {
    // top-down
    int answer = 0;
    memset(memo, -1, sizeof(memo));
    memset(memo2, -1, sizeof(memo2));

    int size = money.size();

    memo[0] = money[0];
    memo[1] = memo[0];
    for(int i=2; i<size-1; i++){ // 첫번째 μš”μ†Œμ—μ„œ μ‹œμž‘ν•˜λ©΄ λ§ˆμ§€λ§‰ μš”μ†Œ μ œμ™Έ
        memo[i] = max(memo[i-2] + money[i], memo[i-1]);
    }

    memo2[0] = 0;
    memo2[1] = money[1];
    for(int i=2; i<size; i++){ // λ‘λ²ˆμ§Έ μš”μ†Œμ—μ„œ μ‹œμž‘ν•˜λ©΄ λ§ˆμ§€λ§‰ μš”μ†Œ 포함
        memo2[i] = max(memo2[i-2] + money[i], memo2[i-1]);
    }

    answer = max(memo[size-2], memo2[size-1]);

    return answer;
}

 

<점화식 bottom-up>

#include <string>
#include <vector>
#include <cstring>
#include <algorithm>

using namespace std;
int memo[1000001];
int memo2[1000001];

int solution(vector<int> money) {
    // bottom-up
    int answer = 0;
    memset(memo, -1, sizeof(memo));
    memset(memo2, -1, sizeof(memo2));

    int size = money.size();

    memo[0] = money[0];
    memo[1] = memo[0];
    for(int i=0; i<size-2; i++){
        memo[i+2] = max(memo[i+2], memo[i] + money[i+2]);
        memo[i+1] = max(memo[i+1], memo[i]);
        // size-2λ₯Ό κ΅¬ν•˜λŠ”λ° μ΅œλŒ€ size-1κΉŒμ§€ λ‚˜μ˜€λ―€λ‘œ ν•„μš”μ—†λŠ” 연산이 좔가됨
    }

    memo2[0] = 0;
    memo2[1] = money[1];
    for(int i=0; i<size-1; i++){
        memo2[i+2] = max(memo2[i+2], memo2[i] + money[i+2]);
        memo2[i+1] = max(memo2[i+1], memo2[i]);
    }

    answer = max(memo[size-2], memo2[size-1]);

    return answer;
}

 

μ˜€λ‹΅μ½”λ“œ <μž¬κ·€ν•¨μˆ˜>

#include <iostream>
#include <vector>
#include <algorithm>
#include <string>
#include <cstring>

using namespace std;

int N;
vector<int> moneyArr;
int memo[1000001];

bool isBitmapEmpty(vector<int>& vec) {
    for (int i = 0; i < vec.size(); i++) {
        if (vec[i] == 1)
            return false;
    }
    return true;
}

int stillMoney(vector<int>& bitmap, int prev) {
    if (isBitmapEmpty(bitmap)) // 더이상 ν›”μΉ μˆ˜ μžˆλŠ” 집이 μ—†μœΌλ©΄ 0 return
        return 0;

    int maxMoney = 0; // μ΅œλŒ€ ν›”μΉœ 돈
    for (int i = prev; i < N; i++) { // ν•œλ°”ν€΄ 돌게 되면 μžλ™μœΌλ‘œ forλ¬Έ μ’…λ£Œ
        vector<int> houses(bitmap);
        if (houses[i] == 0) // ν›”μΉ  수 μ—†μœΌλ©΄
            continue;

        if (memo[i] != -1) {
            // memoκ°€ 있으면
            maxMoney = max(maxMoney, memo[i]);
            continue;
        }

        houses[i] = 0; // 이미 ν›”μ³€μœΌλ―€λ‘œ 더이상 ν›”μΉ  수 μ—†μŒ
        houses[(i - 1 + N) % N] = 0; // 이전 집은 μΈμ ‘ν•΄μžˆμœΌλ―€λ‘œ ν›”μΉ  수 μ—†μŒ
        houses[(i + 1) % N] = 0; // 이후 집

        int tmpMoney = stillMoney(houses, i + 2) + moneyArr[i];
        if (maxMoney < tmpMoney) {
            maxMoney = tmpMoney;
        }
    }
    memo[prev] = maxMoney;
    return maxMoney;
}

int solution(vector<int> money) {
    moneyArr = money;
    N = moneyArr.size(); // μ§‘μ˜ 개수 μ €μž₯
    vector<int> bitmap(N, 1); memset(memo, -1, sizeof(memo));
    int res = stillMoney(bitmap, 0);

    bitmap = vector<int>(N, 1); memset(memo, -1, sizeof(memo));
    res = max(res, stillMoney(bitmap, 1));
    return res;
}

 

κ²°κ³Ό

<점화식 top-down>

 

<점화식 bottom-up>

 

<μž¬κ·€ - νš¨μœ¨μ„± 0점>

bitmap으둜 체크할 ν•„μš” μ—†λŠ”λ° μ²΄ν¬ν•΄μ„œ 그런 λ“― ν•˜λ‹€.

λ°˜μ‘ν˜•