백준 14697 - 방 배정하기

Updated:

C++

14697 번 - 방 배정하기

문제

방의 정원을 나타내는 서로 다른 세 자연수와 전체 학생 수를 나타내는 자연수 하나가 주어졌을 때, 배정된 모든 방에 빈 침대가 없도록 방 배정이 가능한지를 결정하는 프로그램을 작성하시오. 문제 출처

접근 방법

문제 형태가 재귀함수를 요구한다고 판단하여 재귀함수로 접근하였다.
하지만 재귀함수로 문제를 해결하기 위해서는 O(3^N)의 시간복잡도를 요구하여 시간 초과라는 결과를 얻는다.
따라서 단순하게 반복문 3개를 통해 O(N^3)의 시간복잡도로 해결하였다.

두번째는 다이나믹 프로그래밍을 통하여 해결하였다.
만약 주어진 방의 크기가 3 5 7라고 생각하자, 그렇다면 사람이 각각 3, 5, 7명 일때 각 방의 크기에 맞게 배정이 된다.
즉 위의 3, 5, 7명에서 3을 먼저 본다. 이 3명에서 각 방의 크기 3, 5, 7를 더한 6, 8, 10명의 사람이 있을 때 빈 침대가 없도록 방 배정이 가능하게 되는 것이다.
이에 따라 배정 가능한 사람의 수를 계속 더하며, 만약 주어진 수가 위 덧셈의 결과에 없는 경우에 0이 되며 이는 빈 침대가 없도록 방 배정이 불가능하다는 것이다.

구현 - Loop

반복문 3개를 통하여 각 방의 사이즈를 하나씩 증가하여 사람의 크기가 맞는지 확인한다.

코드 - Loop

#include <iostream>
#include <vector>
#include <string>

using namespace std;

int roomSize[3], total;
bool result = false;
bool DFS(int a, int b, int c);
void forloop();
int main() {
    ios::sync_with_stdio(false);
    cin.tie(NULL);

    for (int i = 0; i < 3; i++) {
        cin >> roomSize[i];             //각 방 사이즈 3개 저장
    }
    cin >> total;
    forloop();
    cout << result;
}

void forloop() {
    for (int i = 0; i < 100; i++) {
        for (int j = 0; j < 100; j++) {
            for (int k = 0; k < 100; k++) {
                if ((i * roomSize[0]) + (j * roomSize[1]) + (k * roomSize[2]) == total) {               //세 방의 크기의 합이 주어진 사람 수 이면 성공 후 리턴
                    result = 1;
                    return;
                }
            }
        }
    }
}
//결과는 나오지만, 시간초과가 된다.
bool DFS(int a, int b, int c) {
    int sum = (a * roomSize[0]) + (b * roomSize[1]) + (c * roomSize[2]);
    if (sum > total) {
        return false;
    }
    else if (sum == total) {
        result = 1;
        return true;
    }
    
    if (DFS(a + 1, b, c))
        return true;
    if (DFS(a, b + 1, c))
        return true;
    if (DFS(a, b, c + 1))
        return true;

    return false;
}

구현 - DP

최대 사람의 수는 300명 이므로, 1부터 300까지의 수를 담을 수 있는 배열을 선언한다.
사람의 수를 1부터 주어진 사람의 수 까지 1씩 더해가며, 해당 사람의 수 일때 빈침없 방 배정이 가능한지 DP로 확인한다.
역으로 생각하면, 현재의 사람의 수가 15명이고 방의 크기가 3, 5, 7이면 / 이 15명에서 3, 5, 7을 뺀 12 - 10 - 8 명의 방 중 하나라도 빈침없이 가능하면 15명의 사람의 수도 빈침없이 가능하다.
따라서 현재 사람의 수에서 방의 크기만큼 빼야 하므로, 현재 사람의 수가 방의 크기보다 작은 경우를 대비하기 위해 조건문으로 확인한다.

코드 - DP

#include <iostream>
#include <vector>
#include <string>

using namespace std;

int roomSize[3], total;
bool result = false;
void dp();
int main() {
    ios::sync_with_stdio(false);
    cin.tie(NULL);

    for (int i = 0; i < 3; i++) {
        cin >> roomSize[i];
    }
    cin >> total;
    dp();
    cout << result;
}

void dp() {
    dpNum[0] = 1;               //처음 3개의 방 크기에 빈침없 방 배정이 가능하다고 나타내는 수 1

    for (int human = 1; human <= total; human++) {
        if (human >= roomSize[0]) {             //사람의 수가 첫번째 방의 크기보다 클 때
            if (human >= roomSize[1]) {         //사람의 수가 두번째 방의 크기보다 클 때
                if (human >= roomSize[2]) {     //사람의 수가 세번째 방의 크기보다 클 때
                    dpNum[human] = dpNum[human - roomSize[0]] + dpNum[human - roomSize[1]] + dpNum[human - roomSize[2]];
                }
                else {
                    dpNum[human] = dpNum[human - roomSize[0]] + dpNum[human - roomSize[1]];
                }
            }
            else {
                dpNum[human] = dpNum[human - roomSize[0]];
            }
        }
    }
    if (dpNum[total] != 0)      //0이 아닐 시에는 앞 선 빈침없 방의 사람의 수에서 더한 것이므로, 빈침없을 만들 수 있다.
        result = 1;
}

후기 및 개선할 점