Skip to content
64 changes: 64 additions & 0 deletions BOJ/1000-5000번/DH_1967_2.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
import java.io.*;
import java.util.*;

/*
* 트리의 지름
*/

public class DH_1967_2 {
static class Node {
int e, w;
public Node(int e, int w) {
this.e = e;
this.w = w;
}
}
static ArrayList<Node> adj[];
static int maxIdx, maxDis;

public static void main(String[] args) throws Exception {
// System.setIn(new FileInputStream("./input/BOJ1967.txt"));

BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
int n = Integer.parseInt(br.readLine());

adj = new ArrayList[n + 1];
for(int i = 0; i < adj.length; i++) adj[i] = new ArrayList<Node>();

StringTokenizer st;
for(int i = 0; i < n - 1; i++) {
st = new StringTokenizer(br.readLine());
int s = Integer.parseInt(st.nextToken());
int e = Integer.parseInt(st.nextToken());
int w = Integer.parseInt(st.nextToken());

adj[s].add(new Node(e, w));
adj[e].add(new Node(s, w));
}

boolean[] v = new boolean[n + 1]; // 방문배열
v[1] = true; // 임의의 시작점
dfs(1, 0, v); // 임의의 시작점에서부터 dfs 시작

v = new boolean[n + 1]; // 방문배열 다시 초기화
v[maxIdx] = true; // max: 처음 시작점(1)에서부터 가장 먼 지점
dfs(maxIdx, 0, v); // 처음 시작점(1)에서부터 가장 먼 지점을 기준으로 가장 먼 지점 구하기

System.out.println(maxDis);
}

static void dfs(int start, int dis, boolean[] v) {
if(dis > maxDis) { // dis: start노드까지 가기 위한 가중치
maxIdx = start;
maxDis = dis;
}

for(Node next: adj[start]) {
if(v[next.e]) continue;

v[next.e] = true;
dfs(next.e, dis + next.w, v);
v[next.e] = false;
}
}
}
59 changes: 59 additions & 0 deletions BOJ/1000-5000번/DH_2110_2.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
import java.io.*;
import java.util.*;

/*
* 공유기 설치
* 집의 좌표: x1, ..., xn
* 공유기 C개를 설치할 때, 인접한 거리를 가능한 크게 하여 설치하기
* 집의 개수: N, 공유기 개수: C
*/

public class DH_2110_2 {
public static void main(String[] args) throws Exception {

BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
StringTokenizer st = new StringTokenizer(br.readLine());

int N = Integer.parseInt(st.nextToken()); // 집의 개수
int C = Integer.parseInt(st.nextToken()); // 공유기의 개수

int[] arr = new int[N];

int s = 0, e = 0;

for(int i = 0; i < N; i++) {
arr[i] = Integer.parseInt(br.readLine());
e = Math.max(e, arr[i]);
}

// 이분탐색을 위한 정렬
Arrays.sort(arr);

// 두 공유가 사이 거리의 최대값 → upper bound
while(s <= e) {
int m = (s + e) / 2; // 사이 간격이 tmp 일 때, 설치할 수 있는 공유기의 개수 구하기
int cnt = getCnt(arr, m);

// tmp일 때, 설치해야 되는 공유기 개수가 작다면 크기 줄이기
if(cnt < C) e = m - 1;
else s = m + 1;
}

System.out.println(e);
}

// 공유기 사이 최대 거리가 tmp일 때, 설치해야 되는 공유기 개수
// 왼쪽에 설치할 수록, 공유기를 최대한 많이 멀리 설치할 수 있음 → 첫 번째 집에 무조건 공유기 설치
static int getCnt(int[] arr, int tmp) {
int cnt = 1, prev = arr[0];

for(int i = 1; i < arr.length; i++) {
if(arr[i] - prev >= tmp) {
cnt += 1;
prev = arr[i];
}
}

return cnt;
}
}
58 changes: 58 additions & 0 deletions BOJ/1000-5000번/DH_2805_2.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
import java.io.*;
import java.util.*;

/*
* 나무 자르기
*/

public class DH_2805_2 {
public static void main(String[] args) throws Exception {

BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
StringTokenizer st = new StringTokenizer(br.readLine());

int N = Integer.parseInt(st.nextToken());
int M = Integer.parseInt(st.nextToken());

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

// s가 arr의 최솟값보다 작아질 수 있으므로 0으로 설정해주기
long s = 0, e = Integer.MIN_VALUE;

int[] arr = new int[N];

for(int i = 0; i < N; i++) {
arr[i] = Integer.parseInt(st.nextToken());
e = Math.max(e, arr[i]);
}

Arrays.sort(arr);

// upper bound 구하기
while(s <= e) {
long m = (s + e) / 2;

long totalCutLength = getTotalCutLength(arr, m);

// upper bound → 같을 때, 시작점 옮기기
if(totalCutLength >= M) s = m + 1;
else e = m - 1;
}

// upper bound 구하는 것이기 때문에 e 출력
System.out.println(e);
}

// m을 제한으로 했을 때, 잘리는 나무의 합계
static long getTotalCutLength(int[] arr, long m) {

long result = 0;

for(long a: arr) {
if(a <= m) continue;
result += (a - m);
}

return result;
}
}
110 changes: 110 additions & 0 deletions BOJ/5001-10000번/DH_5021_2.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
import java.io.*;
import java.util.*;

/*
* 왕위 계승
*/

public class DH_5021_2 {

static HashMap<String, Integer> nameToIdx = new HashMap<String, Integer>();
static int[] indegree; // 진입차수 배열
static double[] power; // 혈통 점수
static int idx;

public static void main(String[] args) throws Exception {
System.setIn(new FileInputStream("./input/BOJ5021.txt"));

BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
StringTokenizer st = new StringTokenizer(br.readLine());

int N = Integer.parseInt(st.nextToken()); // 가족 정보
int M = Integer.parseInt(st.nextToken()); // 왕위 계승 주장 사람 정보

// 가족 정보가 N개이기 때문에, 사람은 최대 3N명까지 나올 수 있음!
indegree = new int[3 * N];
power = new double[3 * N];

// 나라를 세운 사람 정보
String s = br.readLine();
nameToIdx.put(s, idx);
power[idx] = 1;
idx += 1;

// 인접 리스트 저장
ArrayList<ArrayList<Integer>> adj = new ArrayList<ArrayList<Integer>>();
for(int i = 0; i < 3 * N; i++) adj.add(new ArrayList<Integer>());

// 입력받는 가족 정보를 기반으로 인접 리스트 & 진입차수 배열 만들기
for(int i = 0; i < N; i++) {
st = new StringTokenizer(br.readLine());

String s1 = st.nextToken(); // 자식
String s2 = st.nextToken(); // 부모 1
String s3 = st.nextToken(); // 부모 2

putName(s1);
putName(s2);
putName(s3);

indegree[nameToIdx.get(s1)] += 2;
adj.get(nameToIdx.get(s2)).add(nameToIdx.get(s1));
adj.get(nameToIdx.get(s3)).add(nameToIdx.get(s1));
}

// 위상정렬을 하기 위해 사용하는 큐
ArrayDeque<Integer> q = new ArrayDeque<>();

// 진입차수 배열이 0인 것들만 우선 큐에 넣어줌
for(String key: nameToIdx.keySet()) {
int idx = nameToIdx.get(key);

if(indegree[idx] != 0) continue;
q.add(idx);

// 혈통점수가 0이면서 들어오는 간선이 없는 경우는 왕족이 아닌 사람이므로
// 혈통점수를 0.5로 바꿔주기
if(power[idx] == 0) power[idx] = 0.5;
}

// 위상정렬
while(!q.isEmpty()) {
int current = q.poll();

for(int next: adj.get(current)) {
// 진입차수 배열을 하나씩 없애기
indegree[next]--;

// 연결된 노드들의 혈통 점수 계산해주기
power[next] += power[current] / 2;

// 진입차수가 0이 된다면 큐에 넣어주기
if(indegree[next] == 0) {
q.add(next);
}
}
}

double maxPower = 0;
String result = null;

// 왕위계승을 주장하는 사람들 중에서 혈통 점수가 가장 큰 사람 이름 출력하기
for(int i = 0; i < M; i++) {
String name = br.readLine();

int key = nameToIdx.getOrDefault(name, -1);

if(key == -1) continue;
if(maxPower < power[key]) {
maxPower = power[key];
result = name;
}
}

System.out.println(result);
}

static void putName(String s) {
if(!nameToIdx.containsKey(s)) nameToIdx.put(s, idx++);
}
}
53 changes: 53 additions & 0 deletions BOJ/5001-10000번/DH_7579_2.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
import java.io.*;
import java.util.*;

/*
* 앱
*/

public class DH_7579_2 {
public static void main(String[] args) throws Exception {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
StringTokenizer st = new StringTokenizer(br.readLine());

int N = Integer.parseInt(st.nextToken());
int M = Integer.parseInt(st.nextToken());

int[] weight = new int[N + 1];

st = new StringTokenizer(br.readLine());
for(int i = 1; i < weight.length; i++) weight[i] = Integer.parseInt(st.nextToken());

int[] cost = new int[N + 1];
st = new StringTokenizer(br.readLine());

int costSum = 0;

for(int i = 1; i < cost.length; i++) {
cost[i] = Integer.parseInt(st.nextToken());
costSum += cost[i];
}

// 1 ≤ M ≤ 10,000,000이기 때문에 바이트에 대해 2차원 배열을 만들면 메모리 초과가 발생함!
// knapsack[i][j]: i번째 바이트까지 확인했을 때, j비용을 사용한 경우 추가로 확보할 수 있는 메모리 크기
int[][] knapsack = new int[N + 1][costSum + 1];

int result = 0;

// M바이트를 확보하기 위한 앱 비활성화의 최소 비용 구하기
for(int i = 1; i < weight.length; i++) {
for(int c = 0; c < knapsack[0].length; c++) {
if(cost[i] <= c)
knapsack[i][c] = Math.max(knapsack[i - 1][c - cost[i]] + weight[i], knapsack[i - 1][c]);
else knapsack[i][c] = knapsack[i - 1][c];

if(knapsack[i][c] >= M) {
result = c;
break;
}
}
}

System.out.println(result);
}
}
40 changes: 40 additions & 0 deletions BOJ/5001-10000번/DH_9084_2.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
import java.io.*;
import java.util.*;

/*
* 동전
*/

public class DH_9084_2 {
public static void main(String[] args) throws Exception {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
StringTokenizer st;
StringBuilder sb = new StringBuilder();

int T = Integer.parseInt(br.readLine());

for(int tc = 0; tc < T; tc++) {
int N = Integer.parseInt(br.readLine()); // 동전의 가짓수

int[] arr = new int[N];

st = new StringTokenizer(br.readLine());
for(int i = 0; i < arr.length; i++) arr[i] = Integer.parseInt(st.nextToken());

int M = Integer.parseInt(br.readLine());

int[] dp = new int[M + 1];

// dp[i]: i원을 만들 수 있는 가짓수
dp[0] = 1;

for(int i = 0; i < arr.length; i++) {
for(int j = arr[i]; j < dp.length; j++) {
dp[j] += dp[j - arr[i]];
}
}

System.out.println(dp[M]);
}
}
}
Loading