2021년 7월 17일 토요일 - 오늘도 덥다아..
오늘 올려볼 문제는 2243번 사탕상자 라는 문제이다.
사진을 클릭하면 해당 문제로 이동합니다.
오늘은 딱 보기에는 쉬워보이는 문제를 가져왔다!보기에만 그렇다는거
논리는 간단할 수 있지만 메모리를 어떻게 적게 사용할 수 있는지 고민해야 하는게 가장 큰 핵심인 것이 이 문제다!
입력 예제
확실히 이번 문제는 입력 예제만 보고서는 이해가 힘든 문제이다...
그렇기에 글로 한 번 다시 간략하게 설명해보자면
- 첫째 줄에는 사탕상자에 접근하는 횟수를 나타낸다.
- 이 때 접근이라 하면 사탕을 넣고 빼는 것을 모두 얘기한다.
- 둘째 줄부터는 사탕상자에 접근하는 방법에 대한 입력이 한 줄 단위로 주어진다.
- 1번 숫자가 1이라면, 2번 숫자의 맛을 가진 사탕을 , 3번 숫자만큼 상자에 더한다. (이때 3번 숫자는 음수일 수 있다.)
- 1번 숫자가 2라면, 2번 숫자번째로 맛있는 사탕을 상자에서 꺼내고, 꺼낸 사탕의 맛을 출력한다.
문제에 대한 이해는 생각보다 쉬운편이다.
하지만 이를 제한된 자원으로 구현할 걸 생각하면 머리가 아파올 것이다...
풀이 및 코드
처음 생각한 풀이로는
- 사탕의 맛이 1 ~ 1,000,000까지 이므로 int 타입의 배열을 1,000,005 크기만큼 만든다.
- 이렇게 배열을 만드는 이유는 사탕상자에 들어간 사탕의 개수를 O(1) 빠르기로 접근가능하기 때문이다.
- priority queue를 사용하여 어떤 맛의 사탕이 상자안에 들어가있는지 저장한다.
- priority queue를 사용하는 이유는 정렬을 알아서 해주기 때문에 사용했다.
- 상자에 사탕을 추가할 때는 int 배열에 접근하여 사탕의 개수가 0일 때만 priority queue에 사탕 맛을 추가한다.
- int 배열에는 항상 들어온 입력만큼 개수를 업데이트해준다.
- 상자에서 사탕을 뺄 때는 입력받은 2번 숫자를 0 이하가 되게끔 만들어준다.
- 0 이하로 만드는 과정은 priority queue에서 숫자를 하나 꺼내서, 그 숫자로 int 타입 배열에 접근한 후 그 수를 2번 숫자에 뺀다.
- 0 이하로 만들어준 priority queue에서 나온 숫자를 출력해준다.
이런식으로 구현하는 것이었다.코드 없이 설명하는게 너무 어렵다..
하지만 그 결과로는...
제출 현황(실패)
이와 같이 메모리 초과가 났다.
int배열 크기가 백만이니깐 메모리 크기 4,000,000B, 넉넉하게 4MB였기에 priority queue에서 메모리 초과가 난다는 것을 2번이나 더 시도해보고 깨달았다..
그렇기에 위에서 사용한 priotiry queue를 사용하는 대신 그냥 int배열을 사용하기로 결정했다.
- int타입 배열 100,000 크기만큼 만들고
- 배열에서 사탕상자 안에 들어간 사탕 맛의 개수만큼만 사용할거기에 개수를 저장하고 있는 변수 하나를 만든다.
- 사탕상자에 사탕을 넣을 때마다 사탕 맛의 개수까지 정렬을 진행해준다.
- 사탕을 꺼내는 과정은 priority queue와 비슷하게 진행해주면 된다.
풀이코드
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.util.Arrays;
public class Main {
public static void main(String[] args) throws NumberFormatException, IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(System.out));
// arr은 사탕 개수를 저장하는 배열, tastes는 사탕 맛을 저장하는 배열이다.
int[] arr = new int[1000005], tastes = new int[100005];
// tastes 배열을 높은 수로 채워둔다. (정렬을 편하게 하기 위해서)
Arrays.fill(tastes, Integer.MAX_VALUE);
// index는 사탕 맛의 개수를 저장하는 변수이다.
int n = Integer.parseInt(br.readLine()), index = 0;
for(int a = 0; a < n; a++)
{
String[] input = br.readLine().split(" ");
// 사탕을 꺼낼 때
if(input[0].equals("1"))
{
int cnt = Integer.parseInt(input[1]);
// find는 사탕 맛을 찾고 저장하는 변수이다.
int find = 0;
while(cnt > 0)
{
cnt -= arr[tastes[find++]];
}
find--;
bw.write(tastes[find] + "\n");
// 사탕 개수를 하나 줄인다.
arr[tastes[find]]--;
// 사탕 개수가 0이라면
if(arr[tastes[find]] == 0)
{
// 사탕 개수를 높은 수로 저장한다.(이 과정은 사탕 맛의 개수를 줄이는 과정과 같다. 정렬하면 자연스레 뒤로 밀리기 때문)
tastes[find] = Integer.MAX_VALUE;
// 부분 정렬 후 맛의 개수를 하나 줄인다.
Arrays.sort(tastes, 0, index--);
}
}
// 사탕을 넣을 때
else
{
int taste = Integer.parseInt(input[1]);
// 입력받은 맛이 상자안에 없다면
if(arr[taste] == 0)
{
// 맛을 저장하는 배열에 맛을 추가한다.
tastes[index++] = taste;
}
// 맛의 개수 배열에 입력받은 개수를 더한다.
arr[taste] += Integer.parseInt(input[2]);
// 맛의 개수만큼 부분 정렬을 한다.
Arrays.sort(tastes, 0, index);
}
}
bw.flush();
}
}
제출 화면
오늘은 내가 평소 틀리는 유형인 "틀렸습니다", "시간 초과"가 아닌 "메모리 초과"가 나와서 뇌가 조금 고장났던 것 같다.
그래도 잘 풀어낸 것 같아서 다행이다!
'백준 문제 풀이' 카테고리의 다른 글
[BOJ / 백준] 백준 1043번 문제를 풀어보았다. (ft. Java) (0) | 2021.07.26 |
---|---|
[BOJ / 백준] 백준 1987번 문제를 풀어보았다. (ft. Java) (0) | 2021.07.24 |
[BOJ / 백준] 백준 2578번 문제를 풀어보았다. (ft. Java) (0) | 2021.07.21 |
[BOJ / 백준] 백준 15904번 문제를 풀어보았다. (ft. Java) (0) | 2021.07.16 |
[BOJ / 백준] 백준 1103번 문제를 풀어보았다. (ft. Java) (0) | 2021.07.16 |
[BOJ / 백준] 백준 15904번 문제를 풀어보았다. (ft. Java)
2021년 7월 16일 금요일 - 엄청 덥다아..
오늘 올려볼 문제는 15904번 UCPC는 무엇의 약자일까? 이라는 문제이다.
사진을 클릭하면 해당 문제로 이동합니다.
오늘은 백준을 둘러보다가 재밌어보이는 실버 문제를 가져왔다!몇 없는 설명이 재밌는 문제
문자열 하나를 입력 받아서 이 문자열을 UCPC라는 약자로 줄일 수 있는지 판단하는 것이 이 문제다!
입력 예제
입력 예제만 봐도 문제에 대한 감이 딱 잡힌다!!
풀이 및 코드
설명이 매우 긴 것에 비해서는 매우 간단한 문제이다.
그저 문자열을 문자 하나하나씩 비교해가면서 UCPC라는 문자를 순서대로 가지고 있는지만 판별하면 되기 때문이다.
말로 설명하는 것 보다는 바로 코드를 통해서 설명하는 것이 더 빠를 것 같다!
풀이 코드
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
public class Main {
public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(System.out));
// 문자열이 UCPC 순서를 지키면서 UCPC 문자를 포함하는지 확인하기 위한 index, compare배열을 위해 사용된다.
int index = 0;
// UCPC를 저장하고 있는 배열, 문자열의 문자와 비교할 때 사용된다.
// 0이 포함되어 있는 것은 입력으로 숫자는 들어오지 않는다고 했으므로 배열의 끝을 표현하기 위한 것이라고 생각하면 된다.
char[] compare = {'U', 'C', 'P', 'C', '0'};
String input = br.readLine();
for(int i = 0; i < input.length(); i++)
{
// 만약 문자열의 문자가 index 부분 compare의 값과 같다면
// index 값을 1 증가시킨다.
if(input.charAt(i) == compare[index])
index++;
}
// 만약 index가 4 (compare에서 0)라면 모든 순서를 지키고 UCPC 문자도 포함하고 있는 것이므로 약자로 만들 수 있는 것이다.
if(index == 4)
bw.write("I love UCPC");
// 아니라면 약자로 만들 수 없는 것이다.
else
bw.write("I hate UCPC");
bw.flush();
}
}
제출 화면
매일 블로그에 포스팅 하지는 않겠지만, 오늘은 좀 쉬운 문제로 쉬어가듯이 포스팅해봤다.
워낙 쉬운 문제이기 때문에 보러올 사람은 거의 없겠지만... 그래도 알고리즘 공부를 처음 해보는 사람들에게는 유용한 포스팅이었으면 좋겠다!
'백준 문제 풀이' 카테고리의 다른 글
[BOJ / 백준] 백준 1043번 문제를 풀어보았다. (ft. Java) (0) | 2021.07.26 |
---|---|
[BOJ / 백준] 백준 1987번 문제를 풀어보았다. (ft. Java) (0) | 2021.07.24 |
[BOJ / 백준] 백준 2578번 문제를 풀어보았다. (ft. Java) (0) | 2021.07.21 |
[BOJ / 백준] 백준 2243번 문제를 풀어보았다. (ft. Java) (0) | 2021.07.16 |
[BOJ / 백준] 백준 1103번 문제를 풀어보았다. (ft. Java) (0) | 2021.07.16 |
[BOJ / 백준] 백준 1103번 문제를 풀어보았다. (ft. Java)
2021년 7월 15일 목요일 - 비가 오고 천둥이 와르르 쾅쾅
오늘 올려볼 문제는 1103번 게임이라는 문제이다.
사진을 클릭하면 해당 문제로 이동합니다.
문제만 봐서는 감이 잘 안잡힐 것이다.왜냐하면 내가 그랬으니깐...
하지만 입력 예제들을 보는 순간 감이 딱 잡힐 것이다!!
자 이제 좀 보드게임의 느낌이 난다!
- 각 보드에는 구멍이 있거나 숫자 하나가 적혀있다.
- 게임은 좌표 (1, 1) 에서 시작하며 동전이 있는 보드에서 상, 하, 좌, 우 한 방향으로 이동할 수 있다.
- 이동할 때에는 보드에 적힌 숫자만큼 직진하여야 한다.
- 직진하여 보드게임 판의 크기를 넘어가게 되거나, 보드 위에 있는 구멍에 빠지게 되면 게임은 끝이 난다.
- 이 때 보드게임을 가장 오래동안 즐기고 싶을 때 최대 몇 번 움직일 수 있는지 구하는 것이 이 문제이다!
풀이 및 코드
문제를 보자마자 생각이 든 것은 바로 DFS 기법이었다!
DFS 기법을 사용하면서 구멍에 대한 예외와 범위에 대한 예외만 처리해주고 방문했던 곳을 또 방문하는 경우 무한으로 게임을 진행하는 것이 가능하기에 -1을 리턴하여 따로 처리만 해주면 될 줄 알았으나...
시간초과가 나버렸다...
DFS 특성상 방문했던 곳으로 되돌아와 다른 곳을 방문하는 방식이기 때문에 판의 크기가 커지면 커질 수록 시간 복잡도는 O(방문해야하는 개수 ^ n) 으로 늘어나기 때문에 이에 대한 처리를 해주어야 한다.
그래서 생각한게 DP이다!
DFS를 통해서 탐색을 하다가 해당 좌표에 가장 최대 횟수를 저장하는 방식을 사용하면서
현재 탐색중인 횟수가 해당 좌표에 횟수보다 작을 경우 탐색을 하지 않는 방향으로 코드를 짜서 시간을 단축시켰다.
풀이 코드
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.util.Arrays;
public class Main {
// arr은 보드게임 판, dp는 회수 저장 배열, v는 방문 여부 배열
// result는 결과
static int[][] arr, dp;
static boolean[][] v;
static int result = 0, row, col;
public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(System.out));
String[] input_nums = br.readLine().split(" ");
row = Integer.parseInt(input_nums[0]);
col = Integer.parseInt(input_nums[1]);
// 사실 2씩 크게 동적할당 할 필요는 없지만 해주었다..
arr = new int[row + 2][col + 2];
v = new boolean[row + 2][col + 2];
dp = new int[row + 2][col + 2];
for(int i = 0; i < row + 2; i++)
{
Arrays.fill(v[i], true);
}
// 입력받는 코드 구멍이 입력으로 들어올 경우 -1을 arr에 저장했다.
for(int i = 1; i <= row; i++)
{
String[] input = br.readLine().split("");
for(int j = 0; j < input.length; j++)
{
if(input[j].equals("H"))
arr[i][j + 1] = -1;
else
arr[i][j + 1] = Integer.parseInt(input[j]);
v[i][j + 1] = false;
}
}
solve(1, 1, 0);
bw.write(result + "\n");
bw.flush();
}
// dfs, dp 기법을 사용한 함수
// x, y는 좌표, length는 현재 이동 횟수를 말한다.
public static int solve(int x, int y, int length)
{
// 해당 좌표의 적혀있는 숫자를 go에 저장한다.
int go = arr[y][x];
// 해당 좌표가 구멍이라면
// result보다 현재 이동 횟수가 더 큰지 살펴보고 result를 업데이트한다.
if(go == -1)
{
if(result < length)
result = length;
return 0;
}
// 또한 해당 좌표의 이전 이동 횟수가 이번에 탐색하려는 이동 횟수보다 작다면
// result보다 현재 이동 횟수가 더 큰지 살펴보고 result를 업데이트한다.
if(dp[y][x] < length)
dp[y][x] = length;
// 이번 탐색에서 해당 좌표는 방문한 것으로 표시.
v[y][x] = true;
// 범위 체크 (아래와 같은 형식의 코드가 4번 반복됨)
// 범위를 벗어난다면
// result보다 현재 이동 횟수가 더 큰지 살펴보고 result를 업데이트한다.
if(x + go > col)
{
if(result < length + 1)
result = length + 1;
}
else
{
// 탐색하려고 하는 좌표가 방문했다면
// result를 -1로 만들고 -1을 리턴한다.
if(v[y][x + go])
{
result = -1;
return -1;
}
else
// 탐색하려는 좌표의 이전 이동 횟수보다 이번에 탐색하려는 이동 횟수보다 작다면
if(dp[y][x + go] < length + 1)
// 재귀를 통해서 탐색하려는 좌표를 탐색한다. 이 때 return 값이 -1이라면 -1을 리턴한다.
if(solve(x + go, y, length + 1) == -1)
return -1;
}
if(x - go < 1)
{
if(result < length + 1)
result = length + 1;
}
else
{
if(v[y][x - go])
{
result = -1;
return -1;
}
else
if(dp[y][x - go] < length + 1)
if(solve(x - go, y, length + 1) == -1)
return -1;
}
if(y + go > row)
{
if(result < length + 1)
result = length + 1;
}
else
{
if(v[y + go][x])
{
result = -1;
return -1;
}
else
if(dp[y + go][x] < length + 1)
if(solve(x, y + go, length + 1) == -1)
return -1;
}
if(y - go < 1)
{
if(result < length + 1)
result = length + 1;
}
else
{
if(v[y - go][x])
{
result = -1;
return -1;
}
else
if(dp[y - go][x] < length + 1)
if(solve(x, y - go, length + 1) == -1)
return -1;
}
v[y][x] = false;
return 0;
}
}
제출 화면
처음 시간복잡도 생각을 못한 것 빼면은 내 논리가 괜찮았던 나름 뿌듯한 문제였다.
오늘 처음으로 블로그에 제대로된 글을 적어보는데 이 글이 누군가에게 도움이 됐으면 좋겠다!
'백준 문제 풀이' 카테고리의 다른 글
[BOJ / 백준] 백준 1043번 문제를 풀어보았다. (ft. Java) (0) | 2021.07.26 |
---|---|
[BOJ / 백준] 백준 1987번 문제를 풀어보았다. (ft. Java) (0) | 2021.07.24 |
[BOJ / 백준] 백준 2578번 문제를 풀어보았다. (ft. Java) (0) | 2021.07.21 |
[BOJ / 백준] 백준 2243번 문제를 풀어보았다. (ft. Java) (0) | 2021.07.16 |
[BOJ / 백준] 백준 15904번 문제를 풀어보았다. (ft. Java) (0) | 2021.07.16 |
블로그를 시작해보자!
시작은 그럴듯하게
태어날 때 부터 나는 작문과는 굉장히 먼 유전자를 가지고 있어왔다..
하지만 내 미래를 위해서라도 하기 싫은 것을 해야될 때가 온 것 같다..
그래서 만들어보는 지인이의 코딩 블로그!!
아직 블로그에 무슨 내용을 올릴지 정확하게 구상해둔 것은 없지만 대충
- 백준 문제 풀이
- 학기 중 문제 복습
- 포트폴리오
- 하소연
이 될 것 같다.
앞으로 열심히 해보자!!
printf("Hello Blog!");
'지인이의 말말말' 카테고리의 다른 글
다시 블로그 쓰기가 어려워졌다... (feat. 이직) (0) | 2022.11.21 |
---|---|
좋은 맥 캡처 프로그램을 찾았다! 다시 블로그 쓸 수 있을 듯 (0) | 2022.07.31 |
맥북을 사고 나서 블로그 쓰기가 힘들어졌다..... (0) | 2022.07.01 |
첫 면접을 봤다!! (1) | 2021.12.22 |
프로젝트 준비중... 자료 찾는게 쉽지 않다.. (0) | 2021.07.26 |