알고리즘 문제해결/BOJ

BOJ 1691 석판

havana723 2022. 8. 9. 16:33

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

 

1691번: 석판

첫 줄에는 대리석 원판의 크기를 나타내는 W(가로 길이), H(세로 길이)가 들어있다. 다음 줄에는 우리가 원하는 크기의 개수 N이 있고, 그다음 N줄에는 그 크기들이 역시 가로, 세로 순으로 들어있

www.acmicpc.net

 

dp로 풀 수 있는 문제입니다. 석판은 가로나 세로 방향으로 완전히 잘라야 한다는 점을 생각하면, 석판을 자르는 것을 부분문제로 나눠서 생각할 수 있습니다. 왼쪽 위를 원하는 모양의 석판 중 하나로 채워주면 두 가지 경우가 생깁니다. 가로로 먼저 자르고 세로로 자르는 것과 세로로 먼저 자르고 가로로 자르는 것입니다. 각 경우마다 새로 생기는 석판은 두 개가 되고 해당 석판을 다시 자르는 것으로 생각할 수 있습니다. 석판의 넓이가 0이라면 손실되는 면적은 0, 아무 석판도 끼워넣을 수 없다면 손실되는 면적은 $w \times h$입니다. 이렇게 재귀적으로 구한 두 경우의 답 중 최솟값이 해당 크기의 석판의 답이 됩니다.

 

아래는 코드입니다.

 

#include <bits/stdc++.h>
#define FastIO ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
#define endl '\n'
#define ends ' '
#define FF first
#define SS second
#define pii pair<int,int>

using namespace std;

int T, n, w, h, memo[606][606];
vector<pii> vec;

int dp(int w, int h) {
  if (memo[w][h] != -1) return memo[w][h];

  int ret = w * h;
  for (int i = 0; i < n; i++) {
    auto [ww, hh] = vec[i];
    if (ww > w || hh > h) continue;
    int tmp = min(dp(w - ww, h) + dp(ww, h - hh), dp(w, h - hh) + dp(w - ww, hh));
    ret = min(ret, tmp);
  }

  return memo[w][h] = ret;
}

int32_t main(void) {
  FastIO;
  T = 1;
  //cin >> T;

  while (T--) {
    cin >> w >> h >> n;

    vec.resize(n);
    for (int i = 0; i < n; i++) cin >> vec[i].FF >> vec[i].SS;

    memset(memo, -1, sizeof(memo));
    memo[0][0] = 0;

    cout << dp(w, h) << endl;
  }

  return 0;
}

'알고리즘 문제해결 > BOJ' 카테고리의 다른 글

BOJ 2671 잠수함식별  (0) 2022.08.10
BOJ 14867 물통  (0) 2022.08.10
BOJ 5821 쌀 창고  (0) 2022.08.08
BOJ 2185 직사각형의 합집합  (0) 2022.08.07
BOJ 5502 팰린드롬  (0) 2022.08.04