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
42 changes: 42 additions & 0 deletions parkhayoon/BOJ_11053_가장증가하는부분수열.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
package algo.week01;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.StringTokenizer;

public class BOJ_11053_가장증가하는부분수열 {

static int N; // 수열의 길이 N
static int[] arr; // 수열
static int[] dp; // 선택한 부분 수열의 길이 저장

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());
arr = new int[N];
dp = new int[N];
st = new StringTokenizer(br.readLine());
for (int i=0; i<N; i++)
arr[i] = Integer.parseInt(st.nextToken());

dp();
int result = 0;
for(int i=0; i<N; i++)
result = Math.max(result, dp[i]+1);
System.out.println(result);
}

private static void dp() {
for(int i=0; i<N; i++) {
for(int j=0; j<i; j++) { // 선택한 i값 이전에서 비교
if(arr[j]<arr[i]) // 만약 앞의 값보다 뒤의 값이 더 긴 경우 - 오름차순의 경우, 부분 수열로 추가 가능
dp[i] = Math.max(dp[i], dp[j]+1); // 현재까지 해당 값까지 최대 부분수열의 길이가 더 긴지 확인
}
}
}

}
111 changes: 111 additions & 0 deletions parkhayoon/BOJ_13305_주유소.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
package algo.week01;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.PriorityQueue;
import java.util.StringTokenizer;

/*
* 도시 N개 일직선 도로
* 제일 왼쪽 -> 오른쪽
* 도로 사이 길이가 다를 수 있음
*
* 처음 출발 시 자동차 기름 없어서 주유소에서 기름 넣고 출발
* 기름통 크기 무제한, 얼마든지 많은 기름을 넣을 수 있음
* 1km당 1L 기름 사용
* 각 도시에는 단 하나의 주유소
* 주유소 마다 리터당 가격이 다를 수 있음
* 이동 최소 비용 계산
*
* 입력
* 첫째 줄: 도시의 개수 N(2 ≤ N ≤ 100,000)
* 다음 줄: 인접한 두 도시를 연결하는 도로의 길이 N-1개
* 다음 줄: 주유소의 리터당 가격이 제일 왼쪽 도시부터 순서대로 N개의 자연수
* 제일 왼쪽 도시부터 제일 오른쪽 도시까지의 거리는 1이상 1,000,000,000 이하의 자연수
* 리터당 가격은 1 이상 1,000,000,000 이하의 자연수
*
* 출력
* 제일 왼쪽 도시에서 제일 오른쪽 도시로 가는 최소 비용
*
* 아이디어
* A(출발점) -> C(경유지 : A-B 사이에서 최솟값) -> B(도착점)
* 최솟값 = PriceA * Dist(C-A) + PriceC * Dist(B-C)
* 1) A-C 구간 : A-C 구간 최솟값 찾고 위 과정 반복
* A-D-C 최솟값 = PriceA * Dist(D-A) + PriceD * Dist(C-D) 갱신
* 2) C-B 구간 : 최소값 고정
*
* 풀이 1) 배열로 최솟값 구하기
* 풀이 2) 우선순위 큐로 최솟값 구하기
*
*/
public class BOJ_13305_주유소 {

static class Oil implements Comparable<Oil>{
int idx, price;

public Oil(int idx, int price) {
super();
this.idx = idx;
this.price = price;
}

@Override
public int compareTo(Oil o) {
if(this.price != o.price)
return this.price > o.price ? 1 : -1;
else
return this.idx < o.idx ? 1 : -1;
}

}

static int N; // 도시의 개수 N
static int[] dist; // 누적 도로의 길이 목록
static int[] price; // 리터 당 가격 목록
static long sum; // 비용 저장
static PriorityQueue<Oil> pq = new PriorityQueue<Oil>();

public static void main(String[] args) throws IOException {

BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
N = Integer.parseInt(br.readLine());
dist = new int[N];
price = new int[N];

StringTokenizer st = new StringTokenizer(br.readLine());
dist[0] = 0; // 0에서 0으로 가는 거리 = 0
for(int i=1; i<N; i++) { // 저장 내용 : 0에서 i로 가는 거리의 길이
int temp = Integer.parseInt(st.nextToken());
dist[i] = dist[i-1]+temp;
}
st = new StringTokenizer(br.readLine());
int minIdx = 0;
for(int i=0; i<N; i++) {
price[i] = Integer.parseInt(st.nextToken());
pq.add(new Oil(i, price[i])); // 전체 범위에서 최소 기름값을 가지는 위치 구하기
//if(price[i]<price[minIdx])
//minIdx = i;
}
minIdx = pq.poll().idx;
findMin(minIdx, N-1); // 최소 기름값 위치, 그 위치에서 갈 다음 위치
System.out.println(sum);

}

private static void findMin(int idx, int lastIdx) {
sum += (long)(dist[lastIdx]-dist[idx])*price[idx]; // 경유지 -> 도착점 비용 계산
if(idx==0) return; // 경유지 = 시작점이면 종료
int minIdx = 0; // 현재 최소 기름값 위치 이전의 최소 기름값 위치 갱신
//for(int i=0; i<idx; i++) {
//if(price[i]<price[minIdx])
//minIdx = i;
//}
while(!pq.isEmpty()) {
minIdx = pq.poll().idx;
if(minIdx<idx) // 이전 최솟값 위치보다 더 앞에있는 최솟값이면 갱신 후 그 위치에서부터 다시 계산
break;
}
findMin(minIdx, idx);
}
}
109 changes: 109 additions & 0 deletions parkhayoon/BOJ_14501_퇴사.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.PriorityQueue;
import java.util.StringTokenizer;

/*
문제
퇴사일: 오늘부터 N+1일
남은 N일 동안 최대한 많은 상담
하루에 하나씩 서로 다른 사람의 상담
각각의 상담: 완료까지 걸리는 시간 Ti, 상담했을 때 받을 수 있는 금액 Pi
하루에 여러 개의 상담을 할 순 없음
이때 얻을 수 있는 최대 수익을 구하시오

입력
첫째 줄: 날짜 N (1 ≤ N ≤ 15)
N개 줄: 1일부터 N일까지 Ti, Pi (1 ≤ Ti ≤ 5, 1 ≤ Pi ≤ 1,000)

출력
얻을 수 있는 최대 이익

아이디어
dp[]
1) 1일까지 얻을 수 있는 최대이익 → 2일까지 얻을 수 있는 최대이익 → …
2) 종료일 순서대로 정렬
시작일 = i
종료일 = i + Ti - 1
cost = Pi
while(종료일 < N)
if(dp[종료일]==0)
dp[종료일] =

0 1 2 3 4 5 6
2 5 2 3 5 8 7
10 20 10 20 15 40 200

정렬
0 2 10 V
2 2 10
3 3 20 V
1 5 20
4 5 15 V
6 7 200
5 8 40

0 1 2 3 4 5 6 7 8 9
4 4 4 4 4 5 7 9 11 13
50 40 30 20 10 10 20 30 40 50

정렬
0 4 50 V
1 4 40
2 4 30
3 4 20
4 4 10
5 5 10 V
6 7 20 - 이론에 오류가 발생! -> sum이 아닌 dp[]를 사용해보자
7 9 30 V
8 11 40
9 13 50
*/
public class BOJ_14501_퇴사 {

static class Work implements Comparable<Work>{
int start, end, price; // 상담 시작일, 종료일, 금액

public Work(int start, int end, int price) {
this.start = start;
this.end = end;
this.price = price;
}


@Override
public int compareTo(Work o) {
if(this.end==o.end)
return this.start>o.start?1:-1;
return this.end>o.end?1:-1;
}
}

public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
int N = Integer.parseInt(br.readLine());
int[] dp = new int[N];

PriorityQueue<Work> pq = new PriorityQueue<>();
for(int i=0; i<N; i++) {
StringTokenizer st = new StringTokenizer(br.readLine());
int time = Integer.parseInt(st.nextToken());
int price = Integer.parseInt(st.nextToken());
pq.add(new Work(i, i+time-1, price)); // 시작일, 종료일(시작일~시작일+기간), 비용
}

while(!pq.isEmpty()) { // 일단은 모든 상담을 확인
Work current = pq.poll(); // 현재 상담 확인
if(current.end>=N) break; // 종료일 기준 정렬 - 초과하면 이후 상담들도 불가능 -> 반복문 종료
dp[current.end] = Math.max(dp[current.end], current.price); // 현재 상담만 선택한 경우 확인
for(int i=0; i<current.start; i++) {
dp[current.end] = Math.max(dp[current.end], dp[i]+current.price); // 겹치지 않는 상담들을 한 경우 확인
}
}
int maxSum = 0;
for(int d : dp) // 기간 별 최적 답 중 최댓값 출력
maxSum = Math.max(maxSum, d);
System.out.println(maxSum);
}
}
116 changes: 116 additions & 0 deletions parkhayoon/BOJ_16234_인구이동.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
package algo.week2;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.StringTokenizer;

/*
* 크기 NxN, 1x1 칸으로 나눠짐
* 각 칸은 나라 하나씩 존재, A[r][c] = r행 c열 인구수
* 1. 국경선 공유 두 국가의 인구차가 L ≤ x ≤ R이면 하루동안 국경 개방
* 2. 모든 국가가 위에 따라 국경선 개방 후 인구 이동 시작
* 3. 국경선이 열려서 연결되어있음 - 연합
* 4. 연합의 각 칸의 인구수 = 연합의 인구수 / 연합 이루는 칸 수, 소수점 버림
* 5. 이동 후 연합 해체, 모든 국경선 닫음
* 인구 이동이 발생하는 기간?
*
* 입력
* 첫째 줄: N,L,R(1 ≤ N ≤ 50, 1 ≤ L ≤ R ≤ 100)
* N개 줄: 각 나라의 인구수(0 ≤ A[r][c] ≤ 100)
* 인구 이동 발생 기간 ≤ 2000
*
* 아이디어
* while(인구 이동 가능한 경우) {
* 방문 배열 초기화
* 배열 전체 탐색 {
* 해당 점에서 dfs 탐색 {...}
* dfs 종료 후 평균 구하기
* tempA에 평균 들어가는 부분 입력
* }
* }
*/
public class BOJ_16234_인구이동 {

static int N, L, R;
static int[][] A;
static int[][] tempA; // i일차 A 이동 후 위치 저장
static int[][] deltas = {{-1,0},{1,0},{0,-1},{0,1}}; // 4방 탐색
static boolean[][] visited; // dfs 방문 확인
static boolean movable = true; // 인구 이동 가능 여부
static int sum, cnt;

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());
L = Integer.parseInt(st.nextToken());
R = Integer.parseInt(st.nextToken());
A = new int[N][N];
tempA = new int[N][N];
visited = new boolean[N][N];

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

int date = -1; // 인구 이동 날짜 수
while(movable) { // 인구 이동이 가능할 때 실행
movable = false; // 일단 움직이지 않는다고 가정 - 추후 탐색에서 인구 이동이 가능할 때 바꿔주기
visited = new boolean[N][N]; // 하루 인구 이동 후 다시 전체 탐색하므로 초기화
tempA = new int[N][N];
// 배열의 모든 부분 탐색
for(int i=0; i<N; i++) {
for(int j=0; j<N; j++) {
// 만약 이전에 이미 탐색한 곳이면 통과
if(visited[i][j]) continue;
// 평균값 구하기 위한 전제조건
visited[i][j]=true; // 현재 지점 방문처리
sum = A[i][j]; // 인구 수의 합
cnt = 1; // 도시 수
dfs(i, j);
if(cnt==1) { // 만약 dfs 탐색했으나 이동 불가능한 경우
tempA[i][j]=A[i][j]; // 원본 값 복사
continue;
}
int avg = sum/cnt; // 평균 구하기(소수점 내림)
// 배열 내부에서 바꿔줘야 하는 연결된 부분 변경
for(int p=0; p<N; p++) {
for(int q=0; q<N; q++) {
if(visited[p][q] && tempA[p][q]==0) // 방문한 점 and 아직 값을 넣지 않은 점
tempA[p][q] = avg;
}
}
}
}
// 인구 이동 완료 - 날짜 1일 추가
date++;
// A 배열을 업데이트
A = tempA.clone();
}

System.out.println(date);
}

private static void dfs(int x, int y) {
// 4방 탐색
for(int d=0; d<4; d++) {
int dx = x+deltas[d][0];
int dy = y+deltas[d][1];
// 범위 밖이거나 이미 방문했거나 두 도시 간 차이가 L 미만, R 초과면 이동 불가
if(dx<0 || dx>=N || dy<0 || dy>=N || visited[dx][dy] || Math.abs(A[x][y]-A[dx][dy])<L || Math.abs(A[x][y]-A[dx][dy])>R) continue;
// 이동 가능한 도시가 있음 - 인구 이동 가능 확인
movable = true;
// 이동하려는 지점을 방문처리
visited[dx][dy] = true;
sum += A[dx][dy];
cnt++;
dfs(dx,dy);
}
}

}
Loading