728x90

문제

 

 

접근 방식

배열에 수를 모두 저장한 후에 정렬하고 끝에서 n번째 인덱스를 출력해도 풀리는 문제지만

우선순위 큐를 이용해서 좀 더 효율적으로 풀 수 있다.

 

최소 힙으로도 풀 수 있지만 최대 힙으로 푸는 것이 더 효율적이니

자바에서 제공하는 우선순위 큐 기준으로는 생성자 파라미터로 정렬 기준을

역순으로 주어 최대 힙을 사용할 수 있다.

 

최대 힙에 입력 받은 수들을 모두 넣어준 후에

n개를 꺼내면 n번째 큰 수가 나오게 된다.

 

풀이

public class Main {

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

		int n = Integer.parseInt(br.readLine());
		int nNum = 0;

		PriorityQueue<Integer> pq = new PriorityQueue<>(Collections.reverseOrder());

		for (int i = 0; i < n; i++) {
			st = new StringTokenizer(br.readLine());

			for (int j = 0; j < n; j++) {
				pq.offer(Integer.parseInt(st.nextToken()));
			}
		}

		while (n-- > 0) {
			nNum = pq.poll();
		}

		System.out.println(nNum);
	}
}

 

728x90

문제

 

 

접근 방식

최소 힙을 구현하는 문제다.

C++의 STL이나 자바의 유틸 클래스에 이미 구현된 우선순위 큐를

사용해서 편하게 풀 수도 있지만 구현해봐야 어떤 원리로

동작하는지를 이해하기 쉽기 때문에 직접 구현해봤다.

 

최소 힙은 부모가 자식보다 작은 값을 가지고 있는 이진 트리 구조여야 하기 때문에

새로운 값을 추가할 때는 가장 마지막 자식 노드에 값을 추가한 후에

해당 노드가 부모 노드보다 큰지 검사하면서 만약 더 작다면 부모 노드와 바꿔주면 된다.

 

반대로 가장 작은 값을 하나 꺼낼 때는 최소 힙의 구조상 무조건 최상위 부모 노드가

가장 작은 값에 해당하기 때문에 해당 값을 출력하고 삭제해주면 된다.

 

풀이

public class Main {

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

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

		MinHeap minHeap = new MinHeap();

		while (n-- > 0) {
			int x = Integer.parseInt(br.readLine());

			if (x != 0) minHeap.offer(x);
			else sb.append(minHeap.poll()).append("\n");
		}

		System.out.println(sb);
	}

	private static class MinHeap {
		int[] heap = new int[100001];
		int size = 0;

		void offer(int x) {
			heap[++size] = x;
			int idx = size;

			while (idx != 1) {
				int cur = idx/2;

				if (heap[idx] > heap[cur]) break;

				swap(idx, cur);

				idx = cur;
			}
		}

		int poll() {
			if (size == 0) return 0;

			int r = heap[1];
			heap[1] = heap[size--];
			int idx = 1;

			while (idx * 2 <= size) {
				int left = idx * 2;
				int right = left + 1;
				int min = left;

				if (right <= size && heap[right] < heap[left]) min = right;
				if (heap[min] >= heap[idx]) break;

				swap(min, idx);

				idx = min;
			}

			return r;
		}

		void swap(int x, int y) {
			int tmp = heap[x];
			heap[x] = heap[y];
			heap[y] = tmp;
		}
	}
}

 

728x90

문제

 

 

접근 방식

우선순위큐 최소힙을 사용해서 풀 수 있는 문제로

직접 구현해서 풀 수도 있지만 자바에서 제공하는 우선순위 큐를 사용하여 풀었다.

 

두 가지 방식으로 풀어봤는데 첫 번째는 우선순위 큐의 생성자에

파라미터로 정렬 기준을 제공해 문제에서 요구하는 순서대로 정렬되게 하는 방법이고

 

두 번째 방법은 우선순위 큐에 모두 절댓값으로 변환해 양수인 값만 저장하면서

맵에 음수인 경우만 카운팅 하는 방법이다.

 

우선 첫 번째 방법부터 살펴보면

정렬기준을 절댓값이 같다면 더 작은 값이 먼저 나와야 하니

abs(x) == abs(y) 라면 x - y를 리턴해주고

두 수의 절댓값이 다르다면 절댓값이 더 작은 수가 앞에 오면 되니

abs(x) - abs(y)를 리턴해주면 된다.

 

두 번째 방법은 자바에서 우선순위 큐의 기본 원리가 최소힙이 적용된 상태니

입력받은 수를 모두 양수로 바꾸어서 큐에 저장한다.

 

이때 입력 받은 수가 음수라면 따로 만들어둔 맵에 해당 절댓값을 키로 가진

값을 1씩 증가시키고 입력으로 0이 들어올 때마다

음수가 카운팅 된 게 남아있으면 음수로 바꾸어 출력해 주고 카운트를 1씩 줄여주면 되고

카운팅이 남아있지 않다면 양수를 출력해 주면 된다.

 

풀이

첫 번째 풀이

public class Main {

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

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

		PriorityQueue<Integer> pq = new PriorityQueue<>((a, b)->
			Math.abs(a) == Math.abs(b) ? (a - b) : (Math.abs(a) - Math.abs(b)));

		for (int i = 0; i < n; i++) {
			int x = Integer.parseInt(br.readLine());

			if (x != 0) {
				pq.offer(x);
			} else {
				sb.append(pq.isEmpty() ? 0 : pq.poll()).append("\n");
			}
		}

		System.out.println(sb);
	}
}

 

두 번째 풀이

public class Main {

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

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

		PriorityQueue<Integer> pq = new PriorityQueue<>(n);
		Map<Integer, Integer> countMap = new HashMap<>();

		for (int i = 0; i < n; i++) {
			int x = Integer.parseInt(br.readLine());

			if (x != 0) {
				int abs = Math.abs(x);
				int count = countMap.getOrDefault(abs, 0);

				if (x < 0) count++;

				countMap.put(abs, count);

				pq.offer(abs);
			} else {
				if (pq.isEmpty()) sb.append(0).append("\n");
				else {
					int num = pq.poll();
					int count = countMap.get(num);

					if (count != 0) {
						sb.append(-num).append("\n");
						countMap.put(num, count - 1);
					} else {
						sb.append(num).append("\n");
					}
				}
			}
		}

		System.out.println(sb);
	}
}

'Java > Algorithms' 카테고리의 다른 글

[백준] 2075번 : N번째 큰 수  (0) 2024.01.22
[백준] 1927번 : 최소 힙  (0) 2024.01.22
[백준] 18808번 : 스티커 붙이기  (0) 2024.01.19
[백준] 1700번 : 멀티탭 스케줄링  (0) 2024.01.17
[백준] 1744번 : 수 묶기  (0) 2024.01.11
728x90

문제

 

접근 방식

문제의 포인트는 배열을 돌리는 것인데 직접 원소들을 움직일 수도 있지만

90도씩 회전할 때마다 배열의 요소들이 어떻게 움직이는지만 안다면

배열을 움직이지 않고도 풀 수 있다.

 

 

만약 위와 같은 n행 m열의 스티커 배열이 주어졌다고 가정했을 때

배열을 90도씩 회전시켜 보겠다.

 

 

우선 오른쪽으로 90도 회전시켰을 때를 살펴보면

행과 열이 뒤집히고 뒤집히기 전의 n행부터 1번째행까지의 첫 열의 값들이

첫 행에 위치하고 있고 그 아래줄부터는 다시 n행부터 1번째행까지의 두 번째 열의 값들이

위치하고 있는 것을 알 수 있다.

 

 

인덱스를 정리하면 위와 같다.

 

 

한 번 더 90도를 회전하면 위와 같고

다시 행과 열이 뒤집혀 원본 상태에서 인덱스만 뒤집히기 때문에

원본 배열을 거꾸로 읽어주면 된다.

 

 

인덱스는 위와 같다.

 

 

마지막으로 90도 회전시키면 위와 같이

다시 행과 열이 뒤집히고 처음 90도 회전시킨 상태의

반대로 배열을 읽어주면 된다.

 

 

인덱스는 위와 같다.

 

실제로 배열의 원소들을 움직일 수도 있지만 배열이 돌아갈 때마다

원소들이 어떻게 움직이는지를 알아둔다면 나중에 비슷한 문제를 풀 때

도움이 될 거 같기에 한 번 규칙을 찾아서 풀어봤다.

 

풀고 나서 비트 연산을 통한 풀이도 봤는데 아직 이런 방법으로는 풀이를 못 떠올리겠다...

 

시뮬레이션 문제들은 기능이나 중복된 코드들을 메서드로 분리하여

간결하고 가독성 있게 풀 수도 있지만 막상 풀고 나서 코드를 정리하려니 귀찮아서

풀 때부터 메서드로 분리하려고 노력해야겠다.

풀이

public class Main {

	private static int n;
	private static int m;
	private static int r;
	private static int c;
	private static int[][] sticker;
	private static int[][] notebook;

	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());
		int k = Integer.parseInt(st.nextToken());
		int result = 0;

		notebook = new int[n][m];

		for (int i = 0; i < k; i++) {
			st = new StringTokenizer(br.readLine());

			r = Integer.parseInt(st.nextToken());
			c = Integer.parseInt(st.nextToken());

			sticker = new int[r][c];

			int plus = 0;

			for (int j = 0; j < r; j++) {
				st = new StringTokenizer(br.readLine());

				for (int l = 0; l < c; l++) {
					int num = Integer.parseInt(st.nextToken());
					sticker[j][l] = num;
					if (num == 1) plus++;
				}
			}

			if (stick()) result += plus;
		}

		System.out.println(result);
	}

	private static boolean stick() {
		for (int rota = 0; rota < 4; rota++) {
			if (rota % 2 == 0) {
				for (int i = 0; i <= n - r; i++) {
					for (int j = 0; j <= m - c; j++) {
						if (rotation(rota, i, j)) return true;
					}
				}
			} else {
				for (int i = 0; i <= n - c; i++) {
					for (int j = 0; j <= m - r; j++) {
						if (rotation(rota, i, j)) return true;
					}
				}
			}
		}
		return false;
	}

	private static boolean rotation(int rota, int st, int ed) {
		int a = 0;
		if (rota == 0) {
			for (int i = 0; i < r; i++) {
				int b = 0;
				for (int j = 0; j < c; j++) {
					if (sticker[i][j] == 1 && notebook[st + a][ed + b] == 1) return false;
					b++;
				}
				a++;
			}
			paste(rota, st, ed);
		} else if (rota == 1) {
			for (int i = 0; i < c; i++) {
				int b = 0;
				for (int j = r - 1; j >= 0; j--) {
					if (sticker[j][i] == 1 && notebook[st + a][ed + b] == 1) return false;
					b++;
				}
				a++;
			}
			paste(rota, st, ed);
		} else if (rota == 2) {
			for (int i = r - 1; i >= 0; i--) {
				int b = 0;
				for (int j = c - 1; j >= 0; j--) {
					if (sticker[i][j] == 1 && notebook[st + a][ed + b] == 1) return false;
					b++;
				}
				a++;
			}
			paste(rota, st, ed);
		} else {
			for (int i = c - 1; i >= 0; i--) {
				int b = 0;
				for (int j = 0; j < r; j++) {
					if (sticker[j][i] == 1 && notebook[st + a][ed + b] == 1) return false;
					b++;
				}
				a++;
			}
			paste(rota, st, ed);
		}

		return true;
	}

	private static void paste(int rota, int st, int ed) {
		if (rota == 0) {
			for (int i = 0; i < r; i++) {
				int b = 0;
				for (int j = 0; j < c; j++) {
					if (sticker[i][j] == 1) notebook[st][ed + b] = 1;
					b++;
				}
				st++;
			}
		} else if (rota == 1) {
			for (int i = 0; i < c; i++) {
				int b = 0;
				for (int j = r - 1; j >= 0; j--) {
					if (sticker[j][i] == 1) notebook[st][ed + b] = 1;
					b++;
				}
				st++;
			}
		} else if (rota == 2) {
			for (int i = r - 1; i >= 0; i--) {
				int b = 0;
				for (int j = c - 1; j >= 0; j--) {
					if (sticker[i][j] == 1) notebook[st][ed + b] = 1;
					b++;
				}
				st++;
			}
		} else {
			for (int i = c - 1; i >= 0; i--) {
				int b = 0;
				for (int j = 0; j < r; j++) {
					if (sticker[j][i] == 1) notebook[st][ed + b] = 1;
					b++;
				}
				st++;
			}
		}
	}
}

 

'Java > Algorithms' 카테고리의 다른 글

[백준] 1927번 : 최소 힙  (0) 2024.01.22
[백준] 11286번 : 절댓값 힙  (1) 2024.01.21
[백준] 1700번 : 멀티탭 스케줄링  (0) 2024.01.17
[백준] 1744번 : 수 묶기  (0) 2024.01.11
[백준] 2170번 : 선 긋기  (1) 2024.01.11
728x90

문제

 

 

접근 방식

플러그를 최소한으로 빼면서 전기용품을 사용하려면

이후에 다시 쓰일 전기용품의 플러그를 빼는 것보단

나중에 쓰일 일이 없는 플러그를 빼는 것이 효율적일 것이고

만약 나중에 쓰인다면 가장 나중에 쓰이는 것을 빼는 게 효율적이다.

 

아래와 같이 상황을 세 가지로 나누어 처리해 주면 된다.

  1. 이미 멀티탭에 꽂힌 전기용품이면 그대로 사용하면 되니 아무런 행동도 하지 않음
  2. 멀티탭에 빈 공간이 있는 경우에는 그대로 빈 공간에 꽂음
  3. 빈 공간이 없으면 앞으로 사용되지 않거나 가장 나중에 사용되는 것을 빼고 새로 꽂음

 

첫 번째 상황을 처리하기 위해 불리언 배열을 만들어

멀티탭에 꽂거나 뺄 때마다 상태를 바꿔주었고

 

두 번째와 세 번째 상황을 처리하기 위해 정수형 배열을 만들어

멀티탭에 꽂혀 있는 플러그들이 어떤 것인지 알 수 있게 저장했다.

 

풀이

public class Main {

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

		int n = Integer.parseInt(st.nextToken());
		int k = Integer.parseInt(st.nextToken());

		int[] history = new int[k + 1];

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

		for (int i = 1; i <= k; i++) {
			history[i] = Integer.parseInt(st.nextToken());
		}

		int tab = n;
		int[] arr = new int[n];
		boolean[] isUsed = new boolean[k + 1];
		int count = 0;

		for (int i = 1; i <= k; i++) {
			int target = history[i];
			int idx = 0;
			int late = 0;

			if (isUsed[target]) continue;
			if (tab > 0) {
				tab--;
				for (int j = 0; j < n; j++) {
					if (arr[j] == 0) {
						arr[j] = target;
						break;
					}
				}
				isUsed[target] = true;
				continue;
			}

			count++;

			for (int j = 0; j < n; j++) {
				int use = arr[j];
				int x = 0;

				for (int l = i + 1; l <= k; l++) {
					if (history[l] == use) {
						x = l;
						break;
					}
				}

				if (x == 0) {
					idx = j;
					break;
				}

				if (x > late) {
					late = x;
					idx = j;
				}
			}

			tab--;
			isUsed[arr[idx]] = false;
			isUsed[target] = true;
			arr[idx] = target;
		}

		System.out.println(count);
	}
}

 

'Java > Algorithms' 카테고리의 다른 글

[백준] 11286번 : 절댓값 힙  (1) 2024.01.21
[백준] 18808번 : 스티커 붙이기  (0) 2024.01.19
[백준] 1744번 : 수 묶기  (0) 2024.01.11
[백준] 2170번 : 선 긋기  (1) 2024.01.11
[백준] 2457번 : 공주님의 정원  (0) 2024.01.10
728x90

문제

 

 

접근 방식

주어진 수열에서 순서 상관 없이 수들을 더하거나 둘을 묶어서 곱하여

가장 큰 값을 얻기 위해서는 빼야 할 때는 가능한 가장 작은 수를

더해줄 때는 가장 큰 수를 더해줘야 한다.

 

두 수를 곱하는 경우를 생각해보면

음수 * 음수 = 양수
음수 * 0 = 0
양수 * 양수 = 양수

 

위와 같이 세 가지 경우가 있고

 

두 수를 더하는 경우를 생각해보면

양수 * 1 < 양수 + 1
양수 * 0 < 양수 + 0

 

위와 같은 경우가 있다.

 

좀 더 간단하게 정리해보면 아래와 같다.

// 음수로 만들 수 있는 최적의 해
음수 * 0이하의 수

// 양수로 만들 수 있는 최적의 해
양수 * 양수
양수 + 1

 

양수는 0과 곱하거나 더하는 경우에는 어떤 이득도 볼 수 없기 때문에

0은 위와 같이 음수와 처리해주는 것이 좋다.

 

수열을 입력 받을 때 0이하의 수가 등장할 때마다

따로 변수에 카운팅을 해준 후에

수열을 오름차순으로 정렬하면

0번 인덱스 부터 카운팅한 만큼까지가 0이하의 수에 해당하고

이후의 인덱스들은 모두 양수라는 것을 알 수 있다.

-3
-2
-1

 

위와 같은 수열이 주어졌을 때를 생각해보면

-3과 -2를 곱하여 6을 만들고 -1을 빼서 5를 얻는 경우가 최적의 해이고

-2
-1

 

위와 같은 경우는 둘이 그대로 곱해 2를 얻는 경우가 최적의 해인데

여기서 알 수 있는 것이 0이하의 개수가 홀수면

마지막 인덱스를 제외한 값들은 서로 곱하고 마지막만 빼주면 되고

개수가 짝수면 모두 서로 곱해주면 된다.

 

양수의 경우는 반대로 개수가 홀수면

첫 인덱스 값을 더해주고 나머지 값들을 서로 곱해주고

짝수면 모두 서로 곱해주면 된다.

 

이제 정리한 내용들을 토대로

0번 부터 COUNT - 1번 인덱스 까지의 음수들을 처리하는 부분과

COUNT번 부터 N - 1번 까지의 양수들을 처리하는 부분을 계산해주면 된다.

 

풀이

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 count = 0;
		int[] seq = new int[n];

		for (int i = 0; i < n; i++) {
			int x = Integer.parseInt(br.readLine());
			seq[i] = x;
			if (x <= 0) count++;
		}

		Arrays.sort(seq);

		long prev = -1001;
		long sum = 0;

		for (int i = 0; i < count; i++) {
			int cur = seq[i];

			if (i == count - 1 && count % 2 != 0) {
				sum += cur;
				continue;
			}

			if (prev < -1000) {
				prev = cur;
				continue;
			}

			sum += (prev * cur);
			prev = -1001;
		}

		prev = -1001;

		for (int i = count; i < n; i++) {
			int cur = seq[i];

			if (i == count && (n - count) % 2 != 0) {
				sum += cur;
				continue;
			}

			if (prev < -1000) {
				prev = cur;
				continue;
			}

			if (prev * cur == cur) sum += (prev + cur);
			else sum += (prev * cur);
			prev = -1001;
		}

		System.out.println(sum);
	}
}

 

728x90

문제

 

 

접근 방식

1 3
2 5
3 5
6 7

 

위와 같이 일직선 상의 선분의 시작점과 끝점이 주어졌을 때

시작점이 가장 작은 순으로 정렬하고 각 선분을 그어보면

세 가지 경우로 선분을 그을 수 있는데

1 2 3 4 5 6 7
1   3
  2     5
    3   5
          6 7

 

위와 같이 처음 1-3 선분이 있을 때

다음에 오는 2-5 선분은 이전 1-3선분에 겹치면서 길이가 조금 더 긴 경우

3-5 선분은 이전 선분 자체에 모두 겹치는 경우

6-7 선분은 겹치지 않는 새로운 선분인 경우다.

 

완전히 새로운 경우에는 끝점 - 시작점으로 선분의 길이를 구할 수 있고

겹치는 경우에는 겹치지 않는 경우만 계산하면 되기 때문에

현재 선분의 끝점에서 이전 선분의 끝점을 빼주면 되고

완전히 겹치는 경우에는 계산할 필요가 없다.

풀이

public class Main {

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

		int n = Integer.parseInt(br.readLine());
		int[][] xy = new int[n][2];

		for (int i = 0; i < n; i++) {
			st = new StringTokenizer(br.readLine());

			xy[i][0] = Integer.parseInt(st.nextToken());
			xy[i][1] = Integer.parseInt(st.nextToken());
		}

		Arrays.sort(xy, (o1, o2) -> o1[0] != o2[0] ? o1[0] - o2[0] : o1[1] - o2[1]);

		int s = xy[0][0];
		int e = xy[0][1];
		int len = e - s;

		for (int i = 1; i < n; i++) {
			int x = xy[i][0];
			int y = xy[i][1];

			if (y <= e) continue;

			if (x <= e) {
				len += (y - e);
			} else {
				len += y - x;
			}

			e = y;
		}

		System.out.println(len);
	}
}

 

'Java > Algorithms' 카테고리의 다른 글

[백준] 1700번 : 멀티탭 스케줄링  (0) 2024.01.17
[백준] 1744번 : 수 묶기  (0) 2024.01.11
[백준] 2457번 : 공주님의 정원  (0) 2024.01.10
[백준] 1541번 : 잃어버린 괄호  (0) 2024.01.10
[백준] 11501번 : 주식  (1) 2024.01.10
728x90

문제

 

 

접근 방식

우선 문제를 정리해 보면

꽃이 피는 날과 지는 날이 주어졌을 때

피는 날을 포함한 날부터 꽃이 피기 시작하고

지는 날을 포함하지 않은 날까지 꽃이 피어있는다.

 

정원에 꽃이 하나라도 피어 있는 상태를 유지하기 위해선

이전에 핀 꽃이 지기 전이나 지자 마자

바로 다음 꽃이 피어 있어야 하기 때문에

이전에 심은 꽃들 중 가장 늦게 지는 날보다 

전이거나 지는 당일에 꽃이 피는 경우에만 심을 수 있다.

10
2 15 3 23
4 12 6 5
5 2 5 31
9 14 12 24
6 15 9 3
6 3 6 15
2 28 4 25
6 15 9 27
10 5 12 31
7 14 9 1

 

위와 같은 입력이 주어졌을 때

꽃이 빨리 피는 순서대로, 같은 경우에는 빨리 지는 순서대로

먼저 정렬을 해준다.

2, 15, 3, 23
2, 28, 4, 25
4, 12, 6, 5
5, 2, 5, 31
6, 3, 6, 15
6, 15, 9, 3
6, 15, 9, 27
7, 14, 9, 1
9, 14, 12, 24
10, 5, 12, 31

 

위의 경우에 최소한의 꽃을 심는 경우는

2.28 ~ 4.25 >> 4.12 ~ 6.5 >> 6.3 ~ 6.15 >> 6.15 ~ 9.27 >> 9.14 ~ 12.24로

5번 꽃을 심어서 정원에 꽃이 핀 상태를 유지할 수 있다.

 

우선 3월 1일 이전에 피고 이후에 지는 꽃 중에서

가장 늦게 지는 꽃을 시작점으로 한 후에

이후 나머지 꽃들의 주기를 살펴보면서

이전 꽃이 지기 전이나 직후에 필 수 있고

이전 꽃보다 늦게 지는 경우에 꽃을 심는다.

 

조심해야 할 부분은 꽃이 필 수 있는 경우라도

더 효율적인 경우 하나만을 골라야 하기 때문에

이전까지 핀 꽃들 중 가장 늦게 지는 꽃보다

오래 피는 꽃만 선택해야 한다.

 

풀이

public class Main {

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

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

		int[][] flowers = new int[n][4];

		for (int i = 0; i < n; i++) {
			st = new StringTokenizer(br.readLine());

			flowers[i][0] = Integer.parseInt(st.nextToken());
			flowers[i][1] = Integer.parseInt(st.nextToken());
			flowers[i][2] = Integer.parseInt(st.nextToken());
			flowers[i][3] = Integer.parseInt(st.nextToken());
		}

		Arrays.sort(flowers, (o1, o2) -> {
			if (o1[0] != o2[0]) {
				return o1[0] - o2[0];
			} else {
				if (o1[1] != o2[1]) {
					return o1[1] - o2[1];
				} else {
					if (o1[2] != o2[2]) {
						return o1[2] - o2[2];
					} else {
						return o1[3] - o2[3];
					}
				}
			}
		});

		int min = 0;
		int psm = 0;
		int psd = 0;
		int pem = 0;
		int ped = 0;

		for (int i = 0; i < n; i++) {
			int sm = flowers[i][0];
			int sd = flowers[i][1];
			int em = flowers[i][2];
			int ed = flowers[i][3];

			if (sm < 3 || (sm == 3 && sd == 1)) {
				if (em < pem || (em == pem && ed <= ped)) continue;
				min = 1;
				psm = sm;
				psd = sd;
				pem = em;
				ped = ed;
				if (end(pem, min))
					return;
				continue;
			}

			if (min == 0) continue;

			if (sm < psm || sm == psm && sd <= psd) {
				if (em < pem || (em == pem && ed <= ped)) continue;
				pem = em;
				ped = ed;
				if (end(pem, min))
					return;
				continue;
			}

			if (sm < pem || (sm == pem && sd <= ped)) {
				min++;
				psm = pem;
				psd = ped;
				pem = em;
				ped = ed;
			}

			if (end(pem, min))
				return;
		}

		System.out.println(0);
	}

	private static boolean end(int pem, int min) {
		if (pem > 11) {
			System.out.println(min);
			return true;
		}
		return false;
	}
}

 

'Java > Algorithms' 카테고리의 다른 글

[백준] 1744번 : 수 묶기  (0) 2024.01.11
[백준] 2170번 : 선 긋기  (1) 2024.01.11
[백준] 1541번 : 잃어버린 괄호  (0) 2024.01.10
[백준] 11501번 : 주식  (1) 2024.01.10
[백준] 2217번 : 로프  (1) 2023.12.26

+ Recent posts