Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
84 changes: 84 additions & 0 deletions 유병규_13주차/[BOJ-10266] 시계 사진들.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
import java.io.*;
import java.util.*;

public class Main {

public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));

//입력 값
int n = Integer.parseInt(br.readLine());
int[] a = new int[n];
int[] b = new int[n];

StringTokenizer st = new StringTokenizer(br.readLine());
for(int i=0; i<n; i++) {
a[i] = Integer.parseInt(st.nextToken());
}
st = new StringTokenizer(br.readLine());
for(int i=0; i<n; i++) {
b[i] = Integer.parseInt(st.nextToken());
}

//바늘의 각도가 특정 순서대로 주어지지 않아, 정렬
Arrays.sort(a);
Arrays.sort(b);

//a 배열의 각 바늘 간 사잇각을 저장하는 배열
int[] da = new int[n];
int pre = 0;
for(int i=1; i<n; i++) {
da[i-1] = a[i]-a[pre++];
}
//첫 바늘과 마지막 바늘의 사잇각
da[n-1] = a[0]+360000 - a[n-1];

//b 배열의 각 바늘 간 사잇각을 저장하는 배열
int[] db = new int[n];
pre = 0;
for(int i=1; i<n; i++) {
db[i-1] = b[i]-b[pre++];
}
//첫 바늘과 마지막 바늘의 사잇각
db[n-1] = b[0]+360000 - b[n-1];

//실패 함수: pi배열
//pi[i]: 0~i까지의 부분 문자열에서 접두사와 접미사의 최대 길이
int[] pi = new int[n];

int j=0;
for(int i=1; i<n; i++) {
while(j>0 && da[i] != da[j]) {
j = pi[j-1];
}
if(da[i] == da[j]) {
pi[i] = ++j;
}
}

//모든 점을 시작점으로 비교하기 위한 배열
int[] target = new int[2*n];
for(int i=0; i<2*n; i++){
target[i] = db[i%n];
}

//kmp
j=0;
for(int i=0; i<2*n; i++) {
while(j>0 && target[i] != da[j]) {
j = pi[j-1];
}

if(target[i] == da[j]) {
//찾았다면 종료
if(j == n-1) {
System.out.println("possible");
return;
}
j++;
}
}

System.out.println("impossible");
}
}
79 changes: 79 additions & 0 deletions 유병규_13주차/[BOJ-1507] 궁금한 민호.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
import java.io.*;
import java.util.*;

public class Main {

public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));

int n = Integer.parseInt(br.readLine());
//최소 거리 정보
int[][] map = new int[n][n];
//현재 도로 정보
int[][] graph = new int[n][n];
for(int i=0; i<n; i++) {
StringTokenizer st = new StringTokenizer(br.readLine());
for(int j=0; j<n; j++) {
map[i][j] = graph[i][j] = Integer.parseInt(st.nextToken());
}
}

//필수 도로의 시간의 합 = 결과 값
int result = 0;
//다익스트라를 위한 자료 구조
int[] dist = new int[n];
PriorityQueue<Integer> pq = new PriorityQueue<>((o1, o2) -> Integer.compare(dist[o1], dist[o2]));
//모든 도로를 하나씩 제거해보며 해당 도로가 최소한 있어야 하는 필수 도로인지 판별
//i와 j를 잇는 도로를 제거했을 때 i -> j로 가는 최단 거리를 계산
for(int i=0; i<n; i++) {
for(int j=i+1; j<n; j++) {
//다익스트라를 위한 초기화
pq.clear();
Arrays.fill(dist, (int) 1e9);
//i에서 출발
dist[i] = 0;
boolean[] visited = new boolean[n];
pq.offer(i);

while(!pq.isEmpty()) {
int current = pq.poll();

if(visited[current]) continue;
visited[current] = true;
//j까지의 최단거리만 구하면 됨
if(current == j) break;

for(int node=0; node<n; node++) {
if(visited[node]) continue;
//i와 j를 잇는 도로는 없다는 가정
if(current==i && node==j) continue;
if(current==j && node==i) continue;

if(dist[node] <= dist[current] + graph[current][node]) continue;
dist[node] = dist[current] + graph[current][node];

pq.offer(node);
}
}

//i와 j를 잇는 도로를 제거했을 때 i -> j로 가는 최단 거리가 다음과 같을 때
//1. 제거 전보다 클 때 해당 도로는 필수 도로이다.
if(dist[j] > map[i][j]) {
result += map[i][j];
// System.out.println((i+1)+"->"+(j+1));
continue;
}
//2. 제거 전보다 작다면 문제가 잘못됨.
if(dist[j] < map[i][j]) {
System.out.println(-1);
return;
}
//3. 제거 전과 같다면 해당 도로는 필수 도로가 아니므로 도로 정보를 INF 값으로 설정하여 없는 도로로 설정
graph[i][j] = (int) 1e9;
graph[j][i] = (int) 1e9;
Comment on lines +59 to +73
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

complete graph를 미리 만들어놓고 간선을 하나씩 제거하는 방법도 있었군요?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

저도 참고해서 해결한 문제인데, 모든 간선을 하나씩 제거했을 때 이 간선이 최단 거리를 위해서 반드시 필요한 간선인 지 확인하는 방법이 참신하다고 생각했습니다. 여러 간선을 조합과 같이 선택해서 확인하는 것이 아니라 각각의 간선을 확인해서 필요한 간선이면 제거하지 않고 다음 다리를 판단하는 것이 인상적인 풀이 방법이었습니다.

}
}

System.out.println(result);
}
}
92 changes: 92 additions & 0 deletions 유병규_13주차/[BOJ-1561] 놀이 공원.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
import java.io.*;
import java.util.*;

public class Main {
private static int n, m;
private static int[] cost;

public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));

StringTokenizer st = new StringTokenizer(br.readLine());
n = Integer.parseInt(st.nextToken());
m = Integer.parseInt(st.nextToken());

st = new StringTokenizer(br.readLine());

//cost[i]: i번 놀이기구 운행 시간
cost = new int[m+1];
long min = Integer.MAX_VALUE; //가장 작은 운행 시간
for(int i=1; i<=m; i++) {
cost[i] = Integer.parseInt(st.nextToken());
min = Math.min(min, cost[i]);
}

//놀이기구 개수보다 사람이 적다면 바로 반환
if(n <= m) {
System.out.println(n);
return;
}

//이분 탐색(모든 사람이 탈 수 있는 최소 시간)
long left = 0;
long right = n*min;//모두 운행시간이 가장 작은 놀이기구를 탔을 때의 시간
long minTime = right;//찾고자 하는 최소 시간

while(left <= right) {
long mid = left + (right-left)/2;

long count = counting(mid);
if(count >= n) {
minTime = Math.min(minTime, mid);
right = mid-1;
continue;
}
left = mid+1;
}

//모든 사람이 탈 수 있는 시간의 1분 전에 총 몇 명이 탑승할 수 있는지
long count = 0;
long time = minTime-1;
//wait[i]: 다음 사람이 i번 놀이기구를 타기 위해 기다려야 하는 대기 시간
long[] wait = new long[m+1];
for(int i=1; i<=m; i++) {
//사람 수 계산
if(time/cost[i] == 0) count += 1;
else if(time%cost[i] == 0) count += time/cost[i];
else count += time/cost[i]+1;
//대기 시간 계산
wait[i] = time%cost[i] == 0 ? 0 : cost[i] - time%cost[i];
}

//남은 사람 수
long rest = n-count;
//대기 시간이 가장 짧은 순으로 놀이기구 번호 정렬
PriorityQueue<Integer> pq = new PriorityQueue<>((o1, o2) -> {
if(wait[o1] == wait[o2]) return Integer.compare(o1, o2);
return Long.compare(wait[o1], wait[o2]);
});
for(int i=1; i<=m; i++) {
pq.add(i);
}

//마지막 사람이 타는 놀이기구 번호
long result = 0;
for(int i=0; i<rest; i++) {
result = pq.poll();
}
System.out.println(result);
Comment on lines +63 to +78
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

이 부분을 PQ 없이 구현하면 조금 더 효율적인 코드가 될 것 같습니다!

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

확실히 단순 정렬이라 PQ를 사용하지 않고 구현하는 것이 더 효율적인 것 같습니다! 당시에 드디어 풀었다는 기쁨에 당장 생각나는 방법으로 구현했었는데, 좀 더 차분히 문제를 푸는 연습이 필요한 것 같습니다. 리뷰 감사합니다!

}

private static long counting(long time) {
//time 동안 탈 수 있는 총 사람 수 계산
long count = 0;
for(int i=1; i<=m; i++) {
if(time/cost[i] == 0) count += 1;
else if(time%cost[i] == 0) count += time/cost[i];
else count += time/cost[i]+1;
}

return count;
}
}
67 changes: 67 additions & 0 deletions 유병규_13주차/[BOJ-16940] BFS 스페셜 저지.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
import java.io.*;
import java.util.*;

public class Main {

public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));

//초기화
int n = Integer.parseInt(br.readLine());

List<Set<Integer>> graph = new ArrayList<>();
for(int i=0; i<=n; i++) {
graph.add(new HashSet<>());
}
for(int i=0; i<n-1; i++) {
StringTokenizer st = new StringTokenizer(br.readLine());
int a = Integer.parseInt(st.nextToken());
int b = Integer.parseInt(st.nextToken());
graph.get(a).add(b);
graph.get(b).add(a);
}

StringTokenizer st = new StringTokenizer(br.readLine());
int[] order = new int[n];
for(int i=0; i<n; i++) {
order[i] = Integer.parseInt(st.nextToken());
}

//result: 나올 수 있는 순서 집합
List<Set<Integer>> result = new ArrayList<>();
for(int i=0; i<=n; i++) {
result.add(new HashSet<>());
}
// 이 문제는 1부터 시작
result.get(0).add(1);
//result 채우기
boolean[] visited = new boolean[n+1];
visited[1] = true;
for(int i=0,idx=1; i<n; i++,idx++) {
Set<Integer> set = graph.get(order[i]);
for(int node : set) {
if(visited[node]) continue;
visited[node] = true;
result.get(idx).add(node);
}
}

//result(순서 집합)에 맞게 나오는지 체크
int idx = 0;
for(int i=0; i<n; i++) {
Set<Integer> set = result.get(i);
if(set.size() == 0) break;
for(int j=0; j<set.size(); j++) {
if(set.contains(order[idx])) {
idx++;
continue;
}
//만약 해당 순서에 나올 수 없는 숫자라면 0을 리턴
System.out.println(0);
return;
}
}
//전부 통과했다면 1을 리턴
System.out.println(1);
}
}
Loading