백준 7569 - 토마토

문제 링크

생각 및 접근

  • 2차원 토마토 문제는 해본 적이 있다. 3차원 토마토 문제를 처음 겪어보았다.

  • 우선, 토마토의 좌표를 나타내는 struct tomato를 선언했다.

      struct tomato {
          int x;
          int y;
          int z;
          tomato(int a, int b, int c) {
              x = a;  y = b;  z = c;
          }
      };
  • 여섯 방향을 나타내는 dx[], dy[], dz[]를 선언했다.

      int dx[] = { 0, 1, 0, 0, -1, 0 };
      int dy[] = { 0, 0, 1, 0, 0, -1 };
      int dz[] = { 1, 0, 0, -1, 0, 0 };
  • 토마토 정보를 m[101][101][101]에 받는다.

      // 익은 토마토일 경우, 익은 토마토를 기준으로 6 방향으로 나눠 안익은 토마토를 익혀가기 위해서 q에 추가한다.
      if (m[i][j][k] == 1)        q.push(make_pair(tomato(i, j, k), 0));
      // 비어있는 경우, emptyCnt++
      else if (m[i][j][k] == -1)  emptyCnt++;
      // 익지 않은 경우, rareCnt++
      else if (m[i][j][k] == 0)   rareCnt++;
  • 토마토 상자 내에 있는 모든 토마토가 익어있는 경우를 처리한다.

      if (q.size() + emptyCnt == _x * _y * _z) {
          cout << 0;
          exit(0);
      }
  • BFS를 실시한다.

      while (!q.empty()) {
          int x = q.front().first.x;
          int y = q.front().first.y;
          int z = q.front().first.z;
          int day = q.front().second;
          q.pop();
    
          // day에서 제일 큰 값이 전체 토마토가 다 익는 날짜가 된다.
          answer = max(answer, day);
    
          for (int i = 0; i < 6; i++) {
              int xx = x + dx[i];
              int yy = y + dy[i];
              int zz = z + dz[i];
    
              if (isRare(xx, yy, zz)) {
                  // 이제는 익었으므로 하나 줄여준다.
                  rareCnt--;
                  // 익었으므로 1로 표기
                  m[xx][yy][zz] = 1;
                  // 익은 토마토를 기준으로 BFS
                  q.push(make_pair(tomato(xx, yy, zz), day + 1));
              }
          }
      }

코드

#include <bits/stdc++.h>
using namespace std;

struct tomato {
    int x;
    int y;
    int z;
    tomato(int a, int b, int c) {
        x = a;  y = b;  z = c;
    }
};

int dx[] = { 0, 1, 0, 0, -1, 0 };
int dy[] = { 0, 0, 1, 0, 0, -1 };
int dz[] = { 1, 0, 0, -1, 0, 0 };

int m[101][101][101], _x, _y, _z, emptyCnt, rareCnt, answer = -2147000000;
queue< pair<tomato, int> > q;

bool isRare(int xx, int yy, int zz) {
    return xx >= 1 && xx <= _y && yy >= 1 && yy <= _x && zz >= 1 && zz <= _z && m[xx][yy][zz] == 0;
}

int main() {
    ios_base::sync_with_stdio(false);
    cin.tie(NULL);  cout.tie(NULL);

    cin >> _x >> _y >> _z;

    for (int k = 1; k <= _z; k++) {
        for (int i = 1; i <= _y; i++) {
            for (int j = 1; j <= _x; j++) {
                cin >> m[i][j][k];
                if (m[i][j][k] == 1)        q.push(make_pair(tomato(i, j, k), 0));
                else if (m[i][j][k] == -1)  emptyCnt++;
                else if (m[i][j][k] == 0)   rareCnt++;
            }
        }
    }

    if (q.size() + emptyCnt == _x * _y * _z) {
        cout << 0;
        exit(0);
    }

    while (!q.empty()) {
        int x = q.front().first.x;
        int y = q.front().first.y;
        int z = q.front().first.z;
        int day = q.front().second;
        q.pop();

        answer = max(answer, day);

        for (int i = 0; i < 6; i++) {
            int xx = x + dx[i];
            int yy = y + dy[i];
            int zz = z + dz[i];

            if (isRare(xx, yy, zz)) {
                rareCnt--;
                m[xx][yy][zz] = 1;
                q.push(make_pair(tomato(xx, yy, zz), day + 1));
            }
        }
    }

    if (rareCnt == 0)   cout << answer;
    else                cout << -1;
}

채점 결과

'Coding Test > acmicpc' 카테고리의 다른 글

백준 12100 - 2048 Easy (c++)  (0) 2020.09.07
백준 2573 - 빙산 (c++)  (0) 2020.08.31
백준 2644 - 촌수계산 (c++)  (0) 2020.08.28
백준 5557 - 1학년 (c++)  (0) 2020.08.24
백준 1495 - 기타리스트 (c++)  (0) 2020.08.24

백준 2644 - 촌수계산

문제 링크

생각 및 접근

  • 구구절절 말이 길지만, 결국 사람과 사람이 주어질 때, 몇 다리 건너서 만날 수 있는지 구하는 문제였다.
  • m[101][101] : 사람들의 촌수 계산을 위해 인접행렬을 선언했다.
  • tar1tar2가 몇 다리 건너서 만날 수 있는 지 DFS로 풀어보고자 헀다. DFS는 가장 먼저 찾은 해답이 최단 다리라고 보장하지 못하므로, 사실상 모든 경로를 탐색해야 한다. 그나마 탐색하는 경로를 줄이기 위해, 탐색 여부를 저장하는 visit[101]를 선언한다.
  • DFS의 종료 조건
    • 내가 탐색하려는 index가 tar2일 때
    • 최단 거리를 저장하는 answercnt를 비교해서 더 작은 값으로 answer를 업데이트한다.
  • DFS 탐색
      // 사람 수 만큼 탐색
      for (int i = 1; i <= n; i++) {
          // 아직 탐색되지 않은 사람이고, 연결이 되어 있다면 dfs할 수 있다.
          if (visit[i] == 0 && m[index][i] == 1) {
              visit[i] = 1;
              dfs(i, cnt + 1);
              visit[i] = 0;
          }
      }

코드

#include <bits/stdc++.h>
using namespace std;

int m[101][101], visit[101];
int n, a, b, cases, tar1, tar2, answer = 101;

void dfs(int index, int cnt) {
    if (index == tar2) {
        answer = min(answer, cnt);
    }
    else {
        for (int i = 1; i <= n; i++) {
            if (visit[i] == 0 && m[index][i] == 1) {
                visit[i] = 1;
                dfs(i, cnt + 1);
                visit[i] = 0;
            }
        }
    }
}

int main() {
    ios_base::sync_with_stdio(false);
    cin.tie(NULL);  cout.tie(NULL);

    cin >> n >> tar1 >> tar2 >> cases;
    for (int i = 1; i <= cases; i++) {
        cin >> a >> b;
        m[a][b] = 1;
        m[b][a] = 1;
    }

    visit[tar1] = 1;
    dfs(tar1, 0);

    if (answer == 101)  cout << -1;
    else                cout << answer;
}

채점 결과

'Coding Test > acmicpc' 카테고리의 다른 글

백준 2573 - 빙산 (c++)  (0) 2020.08.31
백준 7569 - 토마토 (c++)  (0) 2020.08.28
백준 5557 - 1학년 (c++)  (0) 2020.08.24
백준 1495 - 기타리스트 (c++)  (0) 2020.08.24
백준 2294 - 동전 2 (c++)  (0) 2020.08.19

백준 5557 - 1학년

문제 링크

생각 및 접근

  • 문제 입력을 먼저 분석했다.
    • 처음에 총 숫자의 갯수를 주고, 맨 마지막으로 주는 숫자는 플러스와 마이너스를 한 결과값, 나머지 중간에 있는 숫자는 피연산자들이다.
  • dp[i][j]
    • i번째 피연산자를 플러스 또는 마이너스로 계산했을 때, 결과 j가 나오는 경우의 수를 저장한다.
  • dp[i][j]의 초깃값
    • 첫 피연산자가 k라고 하면, 뺄수는 없으므로 dp[1][k] = 1이 된다.
    • 연산의 초깃값이 k가 되고, k가 될 수 있는 경우의 수가 하나밖에 존재하지 않는다.
  • dp[i][j]의 탐색
    • dp[i - 1]를 순회하면서 피연산자 num를 더하거나 뺄 수 있는 후보를 찾는다. 후보를 찾았고, 그 후보에서 num을 더하거나 뺐을 때 0 이상 20 이하라면, dp[i][j + num] += dp[i - 1][j]; 혹은 dp[i][j - num] += dp[i - 1][j];를 한다.
      for (int i = 2; i <= n - 1; i++) {
        cin >> num;
        // dp[i - 1]에서 num을 더하거나 뺄 수 있는 후보 찾기
        for (int j = 0; j <= 20; j++) {
            // 후보를 찾았다.
            if (dp[i - 1][j] > 0) {
                // j에서 (후보의 연산 결과 값에서) num을 더하거나 뺐을 때 0이상 20이하라면 그 경우의 수를 더해준다.
                if (j + num <= 20)    dp[i][j + num] += dp[i - 1][j];
                if (j - num >= 0)     dp[i][j - num] += dp[i - 1][j];
            }
        }
      }

코드

#include <bits/stdc++.h>
using namespace std;

int n, num;
long long dp[101][21];

int main() {
    ios_base::sync_with_stdio(false);
    cin.tie(NULL);  cout.tie(NULL);

    cin >> n >> num;
    dp[1][num] = 1;

    for (int i = 2; i <= n - 1; i++) {
        cin >> num;
        for (int j = 0; j <= 20; j++) {
            if (dp[i - 1][j] > 0) {
                if (j + num <= 20)    dp[i][j + num] += dp[i - 1][j];
                if (j - num >= 0)     dp[i][j - num] += dp[i - 1][j];
            }
        }
    }

    cin >> num;
    cout << dp[n - 1][num];
}

채점 결과

'Coding Test > acmicpc' 카테고리의 다른 글

백준 7569 - 토마토 (c++)  (0) 2020.08.28
백준 2644 - 촌수계산 (c++)  (0) 2020.08.28
백준 1495 - 기타리스트 (c++)  (0) 2020.08.24
백준 2294 - 동전 2 (c++)  (0) 2020.08.19
백준 1904 - 01타일 (c++)  (0) 2020.08.19

백준 1495 - 기타리스트

문제 링크

생각 및 접근

  • dp[i][j]

    • i번째 음악 볼륨 리스트에서 볼륨을 오르내릴 때, j 크기의 볼륨을 가질 수 있는가.
    • 가질 수 있다면 true, 가질 수 없다면 false.
  • dp[i][j]의 초깃값

    • 아직 아무 음악을 탐색하지 않았으므로, 0번째 음악 리스트에는 초깃값 S 크기의 볼륨을 가질 수 있다.
    • 즉, dp[0][s] = true;
  • dp[i][j] 탐색

    • i번째 음악 볼륨 리스트에서 볼륨을 오르내릴 때, dp[i - 1]를 탐색해서 볼륨을 오르내릴 후보를 찾는다. 후보를 찾고, i번째 음악 볼륨을 오르내려서 범위 내에 있다면, dp[i][오르내린 볼륨 결과]를 true로 만들어준다.

      // 음악을 1번 음악부터 n번 음악까지 탐색한다.
      for (int i = 1; i <= n; i++) {
        // i번째 음악 볼륨을 입력 받는다.
        cin >> v;
      
        // j-for문 : dp[i - 1]를 탐색해서 볼륨을 오르내릴 후보를 찾는다.
        for (int j = 0; j <= m; j++) {
            // 볼륨을 오르내릴 후보를 찾았다
            if (dp[i - 1][j]) {
                if (j + v <= m) dp[i][j + v] = true;
                if (j - v >= 0) dp[i][j - v] = true;
            }
        }
      }

코드

#include <bits/stdc++.h>
using namespace std;

int n, s, m, v;
bool dp[101][1001];

int main() {
    ios_base::sync_with_stdio(false);
    cin.tie(NULL);  cout.tie(NULL);

    cin >> n >> s >> m;
    dp[0][s] = true;

    for (int i = 1; i <= n; i++) {
        cin >> v;
        for (int j = 0; j <= m; j++) {
            if (dp[i - 1][j]) {
                if (j + v <= m) dp[i][j + v] = true;
                if (j - v >= 0) dp[i][j - v] = true;
            }
        }
    }

    bool flag = false;
    for (int i = m; i >= 0; i--) {
        if (dp[n][i]) {
            cout << i;
            flag = true;
            break;
        }
    }
    if (!flag)   cout << -1;
}

채점 결과

'Coding Test > acmicpc' 카테고리의 다른 글

백준 2644 - 촌수계산 (c++)  (0) 2020.08.28
백준 5557 - 1학년 (c++)  (0) 2020.08.24
백준 2294 - 동전 2 (c++)  (0) 2020.08.19
백준 1904 - 01타일 (c++)  (0) 2020.08.19
백준 1699 - 제곱수의 합 (c++)  (0) 2020.08.16

백준 2294 - 동전 2

문제 링크

생각 및 접근

  • 동전의 가치가 주어지고, 여러번 골라서 그 가치의 합이 k원이 되게 하는 최소 동전의 갯수를 출력하고, k원을 만들 수 없다면 -1을 출력하는 문제다.
  • dp[i]
    • i원이 되게 하는 최소 동전의 갯수를 저장한다.
  • 동전을 총 n개 받는다고 하면, 1번 동전을 고려했을 때, 1~2번 동전을 고려했을 때, ... , 1~n번 동전을 고려했을 때를 탐색 한다. 즉, 동전을 하나씩 더 추가하면서 k원이 되게 하는 최소 동전의 갯수를 찾는 것이다.
  • 추가할 동전의 값을 coin이라고 하면, j-for문을 돌려서 기존 dp[j]의 값과 dp[j - coin]에 coin을 추가했을 때의 값을 비교한다. dp[j] = min(dp[j], dp[j - coin] + 1);
      for (int j = coin; j <= k; j++) {
          dp[j] = min(dp[j], dp[j - coin] + 1);
      }

코드

#include <bits/stdc++.h>
#define _MAX 2147000000
using namespace std;

int n, k, coin, dp[10001];

int main() {
    ios_base::sync_with_stdio(false);
    cin.tie(NULL);  cout.tie(NULL);

    cin >> n >> k;

    for (int i = 1; i <= k; i++) {
        dp[i] = _MAX;
    }

    for (int i = 1; i <= n; i++) {
        cin >> coin;
        for (int j = coin; j <= k; j++) {
            dp[j] = min(dp[j], dp[j - coin] + 1);
        }
    }

    if (dp[k] == _MAX)  cout << -1;
    else                cout << dp[k];
}

채점 결과

'Coding Test > acmicpc' 카테고리의 다른 글

백준 5557 - 1학년 (c++)  (0) 2020.08.24
백준 1495 - 기타리스트 (c++)  (0) 2020.08.24
백준 1904 - 01타일 (c++)  (0) 2020.08.19
백준 1699 - 제곱수의 합 (c++)  (0) 2020.08.16
백준 12865 - 평범한 배낭 (c++)  (0) 2020.08.15

백준 1904 - 01타일

문제 링크

생각 및 접근

  • 문제가 구구절절 길었지만, 결국엔 00과 1을 조합해서 n의 길이를 만들었을 때, 몇 개의 숫자를 만들 수 있는지 계산하는 문제였다.
  • dp[i]
    • 00과 1을 조합해서 i의 길이를 만들었을 때, 몇 개의 숫자를 만들 수 있는지 저장
    • 이전 값에서 00을 붙여서 길이가 i인 숫자를 만들 수 있는 경우 : dp[i - 2]
    • 이전 값에서 1을 붙여서 길이가 i인 숫자를 만들 수 있는 경우 : dp[i - 1]
    • ∴ dp[i] = dp[i - 2] + dp[i - 1]

코드

#include <bits/stdc++.h>
using namespace std;

int dp[1000001], n;

int main() {
    ios_base::sync_with_stdio(false);
    cin.tie(NULL);  cout.tie(NULL);

    cin >> n;

    dp[1] = 1;  dp[2] = 2;

    for (int i = 3; i <= n; i++) {
        dp[i] = (dp[i - 1] + dp[i - 2]) % 15746;
    }

    cout << dp[n];
}

채점 결과

'Coding Test > acmicpc' 카테고리의 다른 글

백준 1495 - 기타리스트 (c++)  (0) 2020.08.24
백준 2294 - 동전 2 (c++)  (0) 2020.08.19
백준 1699 - 제곱수의 합 (c++)  (0) 2020.08.16
백준 12865 - 평범한 배낭 (c++)  (0) 2020.08.15
백준 1149 - RGB거리 (c++)  (0) 2020.08.15

백준 1699 - 제곱수의 합

문제 링크

생각 및 접근

  • dp[i]
    • i를 제곱수의 합으로 나타내었을 때 가질 수 있는 항의 최솟값을 저장한다.
  • 우선, dp[i]의 최솟값은 i가 제곱수일 때이므로 1이다. 필자는 cnt라는 변수를 사용해 내가 검사하려는 i가 제곱수인지 판별하였다.
      if (i == cnt * cnt) {
          dp[i] = 1;
          cnt++;
      }
  • i를 제곱수의 합으로 나타낼 때 가질 수 있는 항의 최솟값을 구하기 위해서는 일단 제곱수가 많을수록 유리하다. 따라서 제곱수가 하나 있다고 생각하고 j-for문을 돌렸다.
    • 18 = 16 + 1 + 1 = 9 + 9 인 경우도 있으므로, j-for문을 돌렸어야 했다.
        dp[i] = 2147000000;
        for (int j = 1; j <= cnt - 1; j++) {
            dp[i] = min(dp[i], 1 + dp[i - j * j]);
        }

코드

#include <bits/stdc++.h>
using namespace std;

int n, cnt = 1, dp[100001];

int main() {
    ios_base::sync_with_stdio(false);
    cin.tie(NULL);  cout.tie(NULL);

    cin >> n;
    for (int i = 1; i <= n; i++) {
        if (i == cnt * cnt) {
            dp[i] = 1;
            cnt++;
        }
        else {
            dp[i] = 2147000000;
            for (int j = 1; j <= cnt - 1; j++) {
                dp[i] = min(dp[i], 1 + dp[i - j * j]);
            }
        }
    }

    cout << dp[n];
}

채점 결과

'Coding Test > acmicpc' 카테고리의 다른 글

백준 2294 - 동전 2 (c++)  (0) 2020.08.19
백준 1904 - 01타일 (c++)  (0) 2020.08.19
백준 12865 - 평범한 배낭 (c++)  (0) 2020.08.15
백준 1149 - RGB거리 (c++)  (0) 2020.08.15
백준 15989 - 1, 2, 3 더하기 4 (c++)  (0) 2020.08.12

백준 12865 - 평범한 배낭

문제 링크

생각 및 접근

  • 전형적인 냅색 알고리즘이다.
  • dp[i]
    • 현재 배낭의 무게가 i일 때의 최대 가치를 저장
  • 배낭에 넣을 수 있는 물건이 중복되지 않으므로, j-for문을 역순으로 체킹하면 중복 없이 확인할 수 있다.
      for(int j = k; j >= w; j--){
          dp[j] = max(dp[j], dp[j - w] + v);
      }
    • k는 가방의 제한 무게, w는 현재 검사하려는 물건의 무게, v는 현재 검사하려는 물건의 가치
    • j-for문
      • j를 k부터 w까지 돌린다. j가 w보다 작은 값을 도는 것은 의미가 없다. 현재 검사하려는 물건의 무게가 w이므로, w 미만의 가방 무게에는 검사하려는 물건이 들어갈 수 없다.
      • dp[j]dp[j - w] + v 중 큰 값으로 dp[j]를 업데이트 한다.

코드

#include <bits/stdc++.h>
using namespace std;

int n, k, w, v, dp[100001];

int main() {
    ios_base::sync_with_stdio(false);
    cin.tie(NULL);  cout.tie(NULL);

    cin >> n >> k;
    for(int i = 1; i <= n; i++){
        cin >> w >> v;
        for(int j = k; j >= w; j--){
            dp[j] = max(dp[j], dp[j - w] + v);
        }
    }

    cout << dp[k];
}

채점 결과

'Coding Test > acmicpc' 카테고리의 다른 글

백준 1904 - 01타일 (c++)  (0) 2020.08.19
백준 1699 - 제곱수의 합 (c++)  (0) 2020.08.16
백준 1149 - RGB거리 (c++)  (0) 2020.08.15
백준 15989 - 1, 2, 3 더하기 4 (c++)  (0) 2020.08.12
백준 1890 - 점프 (c++)  (0) 2020.08.10

+ Recent posts