-
Notifications
You must be signed in to change notification settings - Fork 4
[3주차] 백제완 #30
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[3주차] 백제완 #30
Changes from all commits
0c99e0a
0d03b53
a09e502
c933b56
ef1fe60
d2935c6
0ffcf59
17a8a07
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,43 @@ | ||
import java.util.ArrayDeque; | ||
import java.util.Deque; | ||
|
||
public class Main { | ||
|
||
public static void main(String[] args) throws Exception { | ||
int n = read(), w = read(), l = read(); | ||
int[] trucks = new int[n]; | ||
for (int i = 0; i < n; i++) | ||
trucks[i] = read(); | ||
// 트럭의 움직임을 큐로 구현 | ||
Deque<Integer> dq = new ArrayDeque<>(); | ||
// 다리의 길이만큼 빈 트럭을 넣어줌 | ||
for (int i = 0; i < w; i++) | ||
dq.offer(0); | ||
int time = 0, sumWeight = 0, truckIdx = 0; // 현재 시간, 다리 위 트럭의 무게 총합, 트럭의 인덱스 | ||
while (!dq.isEmpty()) { | ||
time++; // 시간 증가 | ||
sumWeight -= dq.poll(); // 트럭을 다리에서 꺼냄 | ||
// 넣어야할 트럭이 남아있고 | ||
if (truckIdx < n) { | ||
// 최대 하중을 넘지않는다면 트럭 삽입 | ||
if (l >= sumWeight + trucks[truckIdx]) { | ||
dq.offer(trucks[truckIdx]); | ||
sumWeight += trucks[truckIdx]; | ||
truckIdx++; | ||
} else | ||
dq.offer(0); // 트럭과 트럭 사이의 빈 공간을 유지 | ||
} | ||
} | ||
System.out.println(time); | ||
} | ||
|
||
// 빠른 입력 함수 | ||
private static int read() throws Exception { | ||
int c, n = System.in.read() & 15; | ||
while ((c = System.in.read()) >= 48) | ||
n = (n << 3) + (n << 1) + (c & 15); | ||
if (c == 13) | ||
System.in.read(); | ||
return n; | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
public class Main { | ||
|
||
public static void main(String[] args) throws Exception { | ||
int t = read(); | ||
int[] dp = new int[10_001]; | ||
dp[0] = 1; | ||
// 중복을 허용하지 않으므로 현재 값에서 -1, -2, -3의 인덱스에 있는 값을 더해줌 | ||
for (int i = 1; i <= 3; i++) | ||
for (int j = i; j < 10_001; j++) | ||
dp[j] += dp[j - i]; | ||
StringBuilder sb = new StringBuilder(); | ||
while (t-- > 0) { | ||
int n = read(); | ||
sb.append(dp[n]).append("\n"); | ||
} | ||
System.out.println(sb); | ||
} | ||
|
||
private static int read() throws Exception { | ||
int c, n = System.in.read() & 15; | ||
while ((c = System.in.read()) >= 48) | ||
n = (n << 3) + (n << 1) + (c & 15); | ||
if (c == 13) | ||
System.in.read(); | ||
return n; | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,61 @@ | ||
import java.util.ArrayDeque; | ||
import java.util.Arrays; | ||
import java.util.Deque; | ||
|
||
public class Main { | ||
|
||
// 나이트의 움직임 | ||
static int[] dx = { -1, -2, -2, -1, 1, 2, 2, 1 }; | ||
static int[] dy = { -2, -1, 1, 2, 2, 1, -1, -2 }; | ||
static int n; | ||
|
||
public static void main(String[] args) throws Exception { | ||
n = read(); | ||
int m = read(); | ||
int x = read(), y = read(); // 초기 나이트 | ||
int[][] EArr = new int[m][2]; // 상대 말의 위치를 저장할 배열 | ||
for (int i = 0; i < m; i++) { | ||
int A = read(), B = read(); | ||
EArr[i] = new int[] { A, B }; // 상대 말의 위치 저장 | ||
} | ||
int[][] board = new int[n + 1][n + 1]; // 각 좌표의 최소 시간을 저장할 배열 | ||
for (int i = 0; i < n + 1; i++) | ||
Arrays.fill(board[i], -1); // 방문 체크를 위해 -1로 초기화 | ||
// BFS | ||
Deque<int[]> dq = new ArrayDeque<>(); | ||
dq.offer(new int[] { x, y }); | ||
board[x][y] = 0; // 초기 방문체크 | ||
while (!dq.isEmpty()) { | ||
int[] cur = dq.poll(); // 현재 나이트의 위치 | ||
for (int i = 0; i < 8; i++) { | ||
int nx = cur[0] + dx[i]; | ||
int ny = cur[1] + dy[i]; | ||
// 다음 위치로 이동할 수 있고, 방문하지 않았다면 | ||
if (isValid(nx, ny) && board[nx][ny] == -1) { | ||
dq.offer(new int[] { nx, ny }); | ||
board[nx][ny] = board[cur[0]][cur[1]] + 1; // 이전 위치의 최소 시간 + 1 | ||
} | ||
} | ||
} | ||
StringBuilder sb = new StringBuilder(); | ||
// 적들의 위치를 순회하면서 최소 시간을 출력 | ||
for (int[] E : EArr) | ||
sb.append(board[E[0]][E[1]]).append(" "); | ||
System.out.println(sb); | ||
} | ||
|
||
// 경계 체크 | ||
private static boolean isValid(int x, int y) { | ||
return 0 < x && x <= n && 0 < y && y <= n; | ||
} | ||
|
||
// 빠른 입력 함수 | ||
private static int read() throws Exception { | ||
int c, n = System.in.read() & 15; | ||
while ((c = System.in.read()) >= 48) | ||
n = (n << 3) + (n << 1) + (c & 15); | ||
if (c == 13) | ||
System.in.read(); | ||
return n; | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,91 @@ | ||
public class Main { | ||
|
||
static int n, m, h; | ||
static boolean[][] ladders; | ||
|
||
public static void main(String[] args) throws Exception { | ||
n = read(); | ||
m = read(); | ||
h = read(); | ||
ladders = new boolean[h][n - 1]; // 사다리가 설치되어 있는지 확인할 배열 | ||
// 미리 설치되어 있는 사다리 입력 | ||
for (int i = 0; i < m; i++) { | ||
int y = read(), x = read(); | ||
ladders[y - 1][x - 1] = true; | ||
} | ||
// 사다리를 3개 이하로 설치해서 올바른지 확인 | ||
for (int i = 0; i <= 3; i++) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 사다리를 3개까지만 설치한다고 가정하고 시뮬레이션을 돌리는게 효과적인 것 같습니다! 👍 |
||
if (placeLadder(0, i)) { | ||
System.out.println(i); | ||
return; | ||
} | ||
} | ||
// 3개 초과한다면 실패, -1 출력 | ||
System.out.println(-1); | ||
} | ||
|
||
// 재귀적 호출로 사다리 설치 | ||
// depth : 설치한 사다리의 수 | ||
// cnt : 설치해야 할 사다리 수 | ||
private static boolean placeLadder(int depth, int cnt) { | ||
// 사다리가 다 설치되었다면 움직임 | ||
if (depth == cnt) | ||
return simulate(); | ||
for (int i = 0; i < h; i++) { | ||
for (int j = 0; j < n - 1; j++) { | ||
// 사다리를 설치할 수 있는 위치라면 | ||
if (isPossible(i, j)) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 저는 사다리 설치하는 부분 되게 조건을 복잡하게 설정했는데, 문제에 대해 진짜 잘 이해하고 딱 필요한 것만 구현하는거 잘 하시는 것 같네여,,, There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @KodaHye |
||
ladders[i][j] = true; // 사다리 설치 후 다음 깊이의 재귀 호출 | ||
if (placeLadder(depth + 1, cnt)) | ||
return true; | ||
// 사다리 설치가 잘못되었다면 | ||
ladders[i][j] = false; // 사다리 해체 (백트래킹) | ||
} | ||
} | ||
} | ||
// 전부 실패 | ||
return false; | ||
} | ||
|
||
// 사다리를 설치할 수 있는지 없는지 확인 | ||
private static boolean isPossible(int y, int x) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 위에서 말씀하신 것처럼 배열로 구현하니까 확실히 깔끔하군요! There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 지영님 아이디어처럼 더욱 근본적인
같은 조건이 있으면 좋았을테지만.. 다들 칭찬해주셔서 만족입니다🐹 |
||
// 현재 위치가 설치되어 있지 않고 | ||
if (ladders[y][x]) | ||
return false; | ||
// 좌, 우에 사다리가 설치되지 않은 경우 | ||
if ((x - 1 >= 0 && ladders[y][x - 1]) || (x + 1 < n - 1 && ladders[y][x + 1])) | ||
return false; | ||
return true; | ||
} | ||
|
||
// 움직임 구현하는 시뮬레이션 | ||
private static boolean simulate() { | ||
for (int i = 0; i < n - 1; i++) { | ||
int num = i; // 초기 위치 | ||
// 내려가면서 좌, 우에 사다리가 있다면 위치 변환 | ||
for (int j = 0; j < h; j++) { | ||
int left = num - 1, right = num; | ||
// 좌측에 사다리가 있다면 왼쪽으로 이동 | ||
if (left >= 0 && ladders[j][left]) | ||
num--; | ||
// 우측에 사다리가 있다면 오른쪽으로 이동 | ||
if (right < n - 1 && ladders[j][right]) | ||
num++; | ||
} | ||
// 처음 위치와 마지막 위치가 같지 않다면 | ||
if (num != i) | ||
return false; | ||
} | ||
return true; | ||
} | ||
|
||
// 빠른 입력을 위한 함수 | ||
private static int read() throws Exception { | ||
int c, n = System.in.read() & 15; | ||
while ((c = System.in.read()) >= 48) | ||
n = (n << 3) + (n << 1) + (c & 15); | ||
if (c == 13) | ||
System.in.read(); | ||
return n; | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,115 @@ | ||
import java.io.BufferedReader; | ||
import java.io.InputStreamReader; | ||
import java.util.ArrayDeque; | ||
import java.util.Deque; | ||
import java.util.StringTokenizer; | ||
|
||
public class Main { | ||
|
||
static int n; | ||
static int[][] board; // 격자 칸 | ||
static int[][] opers; // 각 년도의 이동 규칙 | ||
static boolean[][] supple; // 영양제가 있는 위치 | ||
|
||
// 대각선 움직임 구현 | ||
static int[] dy = { 0, 0, -1, -1, -1, 0, 1, 1, 1 }; | ||
static int[] dx = { 0, 1, 1, 0, -1, -1, -1, 0, 1 }; | ||
|
||
public static void main(String[] args) throws Exception { | ||
BufferedReader br = new BufferedReader(new InputStreamReader(System.in)); | ||
StringTokenizer st = new StringTokenizer(br.readLine()); | ||
n = Integer.parseInt(st.nextToken()); | ||
int m = Integer.parseInt(st.nextToken()); | ||
board = new int[n][n]; | ||
supple = new boolean[n][n]; | ||
for (int i = 0; i < n; i++) { | ||
st = new StringTokenizer(br.readLine()); | ||
for (int j = 0; j < n; j++) | ||
board[i][j] = Integer.parseInt(st.nextToken()); | ||
} | ||
opers = new int[m][2]; // { 방향, 크기 } | ||
for (int i = 0; i < m; i++) { | ||
st = new StringTokenizer(br.readLine()); | ||
opers[i][0] = Integer.parseInt(st.nextToken()); | ||
opers[i][1] = Integer.parseInt(st.nextToken()); | ||
} | ||
// 첫 영양제 위치 | ||
supple[n - 2][0] = true; | ||
supple[n - 2][1] = true; | ||
supple[n - 1][0] = true; | ||
supple[n - 1][1] = true; | ||
// 년도만큼 반복 | ||
for (int year = 0; year < m; year++) { | ||
move(year); // 영양제의 움직임 구현 | ||
grow(); // 영양제 위치의 나무 성장 | ||
cut(); // 크기가 2 이상인 나무를 잘라내고 영양제를 심음 | ||
} | ||
// 남아있는 나무 높이들의 총 합 | ||
int sum = 0; | ||
for (int i = 0; i < n; i++) | ||
for (int j = 0; j < n; j++) | ||
sum += board[i][j]; | ||
System.out.println(sum); | ||
} | ||
|
||
// 영양제의 움직임 구현 | ||
private static void move(int year) { | ||
// 큐를 이용해 기존 영양제의 위치를 저장 | ||
Deque<int[]> dq = new ArrayDeque<>(); | ||
for (int i = 0; i < n; i++) | ||
for (int j = 0; j < n; j++) | ||
if (supple[i][j]) { | ||
supple[i][j] = false; | ||
dq.offer(new int[] { i, j }); | ||
} | ||
// 년도에 따른 이동 방향 및 크기 | ||
int[] oper = opers[year]; | ||
while (!dq.isEmpty()) { | ||
int[] cur = dq.poll(); | ||
// 영양제 위치 이동 | ||
int y = (cur[0] + dy[oper[0]] * oper[1] + n) % n; | ||
int x = (cur[1] + dx[oper[0]] * oper[1] + n) % n; | ||
supple[y][x] = true; // 이동한 영양제 위치 표시 | ||
board[y][x]++; // 영양제가 있는 위치의 나무 성장 | ||
} | ||
} | ||
|
||
// 영양제 위치의 나무 성장 | ||
private static void grow() { | ||
for (int i = 0; i < n; i++) | ||
for (int j = 0; j < n; j++) | ||
// 영양제가 있다면 | ||
if (supple[i][j]) { | ||
int cnt = 0; | ||
for (int k = 1; k <= 4; k++) { | ||
// 대각선 벡터값 | ||
int y = i + dy[k * 2]; | ||
int x = j + dx[k * 2]; | ||
if (isValid(y, x) && board[y][x] > 0) | ||
cnt++; | ||
} | ||
// 대각선에 있는 나무의 수 만큼 성장 | ||
board[i][j] += cnt; | ||
} | ||
} | ||
|
||
// 크기가 2 이상인 나무를 잘라내고 영양제를 심음 | ||
private static void cut() { | ||
for (int i = 0; i < n; i++) | ||
for (int j = 0; j < n; j++) | ||
// 영양제가 없었던 좌표에서 크기가 2 이상인 나무 | ||
if (!supple[i][j]) { | ||
if (board[i][j] >= 2) { | ||
board[i][j] -= 2; | ||
supple[i][j] = true; | ||
} | ||
} else { | ||
// 기존에 있던 영양제는 없애줌 | ||
supple[i][j] = false; | ||
} | ||
} | ||
|
||
private static boolean isValid(int y, int x) { | ||
return 0 <= y && y < n && 0 <= x && x < n; | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,37 @@ | ||
import java.util.Arrays; | ||
class Solution { | ||
public int solution(int distance, int[] rocks, int n) { | ||
int answer = 0; | ||
Arrays.sort(rocks); // 이분 탐색을 위한 정렬 | ||
int l = 1, r = distance; // 이분 탐색의 최소, 최대 경계 설정 | ||
// 이분 탐색을 통해 최적의 최소 거리를 찾음 | ||
while (l <= r) { | ||
int m = (l + r) / 2; // 각 바위 사이의 최소 거리 | ||
// 해당 거리로 지울 수 있는 바위 수 계산 | ||
if (isPossible(distance, rocks, m, n)) { | ||
answer = m; // 가능하면 그 거리를 정답으로 저장 | ||
l = m + 1; // 다음 탐색(최소 거리 중 최댓값)을 위해 왼쪽 경계 재설정 | ||
} else | ||
r = m - 1; // 불가능하면 더 작은 최소 거리를 탐색 | ||
} | ||
return answer; | ||
} | ||
|
||
// 해당 target의 길이로 없앨 수 있는 바위의 개수를 반환 | ||
private boolean isPossible(int distance, int[] rocks, int target, int n) { | ||
int now = 0; // 시작 바위 | ||
int removed = 0; // 제거된 바위 수 | ||
// 두 바위 사이의 거리가 target보다 작다면 없앰 | ||
for (int i = 0; i < rocks.length; i++) { | ||
if (rocks[i] < now + target) | ||
removed++; | ||
else | ||
now = rocks[i]; // 거리가 충분하면 현재 바위를 기준으로 갱신 | ||
} | ||
// 마지막 바위(distance)까지 거리도 확인 | ||
if (distance < now + target) | ||
removed++; | ||
return removed <= n; // 현재 거리로 가능했는지 반환 | ||
// 부등호가 들어가는 이유는 아무거나 지워서 n개를 맞출 수 있어서 상관없음. | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
혹시 클래스를 안만들고, 배열로 많이 구현하시는 이유가 있나요?!!!
저는 배열로 구현하게되면 인덱스가 어떤 정보를 나타내는거였는지 까먹게돼서 클래스로 구현하는 편인데, 궁금합니다!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@KodaHye
이 부분은 저도 항상 코드 작성할 때 고민하는 부분입니다!
일단 저는 자료형이 같고, 단순한 정보(좌표)를 저장할 때는 배열을 주로 이용하는 편이에요!
제가 배열을 주로 사용하는 이유를 생각해봤는데
밖에.. 없는 것 같네요..🤔 아무래도 코딩테스트를 위한 코드니깐 빠르게 작성하려고 그런 것 같아요!
많은 조건을 저장해야하는 경우에는 클래스를 만들어 씁니다!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
저도 BFS 문제 풀이를 보면 Class 나 배열을 사용하는 코드가 있었는데, 둘의 사용했을 때 어떤 차이가 있는지 궁금했었어요!
개인적으로 저는 Class 를 사용했을때 해당 위치를 index 로 이해하지 않고 객체 자체로 이해하니까 더 가독성이 좋고 디버깅을 할때도 이해하기 편했던거 같아요 ㅎㅎ
이번에 BFS를 풀 때 처음으로 Class 를 이용해서 풀어봤는데,
클래스로 생각하니까 현재 위치에 도달했을 때 어떤 정보를 얻을 수 있는지 객체의 필드에 저장할 수 있어서 조금 더 유연성 있는 생각을 할 수 있었던것 같습니다!