배열의 (1, 1)~(n, n)까지 이동할 때, 이동하기 위해 거쳐 간 수들 중 최댓값과 최솟값의 차이가 가장 작아지는 경우를 구하는 문제이다.

배열에서 이동하는 모든 경우를 완전탐색 할 경우 O(4^N)이 걸릴 것이다.

 

이런 경우 최댓값과 최솟값을 차이를 무작정 구하는 방법 보다는,

최댓값과 최솟값을 차이를 정해두고 가능한지 여부를 보는 방법이 더 쉬울 수 있다.

 

 

1차 시도 - 이분탐색을 사용하자

 

처음 생각한 문제 풀이 과정은 아래와 같다.

1. 이진 탐색으로 최대-최소 차이를 정한다.

2. (1, 1) -> (n, n)로 차이 내에 갈 수 있는지 bfs로 탐색한다.

 

이 경우에는 차이를 구하더라도 이에 맞는 쌍을 구해야 하는데,

이때 해당하는 쌍을 구할 때 이중for문을 사용하기보다는 두 포인터를 이용하여 시간을 줄이도록 했다.

import java.util.*;

public class Main {
	public static int dr[] = { 0, 0, 1, -1 };
	public static int dc[] = { 1, -1, 0, 0 };

	public static void main(String[] args) {
		Scanner in = new Scanner(System.in);
		int n = in.nextInt();
		int mat[][] = new int[n][n];
		TreeSet<Integer> set = new TreeSet<Integer>();

		for (int i = 0; i < n; i++) {
			for (int j = 0; j < n; j++) {
				mat[i][j] = in.nextInt();
				set.add(mat[i][j]);
			}
		}

		int[] numbers = set.stream().mapToInt(i -> i).toArray();
		System.out.println(findDifference(numbers, mat, n));
	}

	private static int findDifference(int[] numbers, int[][] mat, int n) { // 이분탐색
		int length = numbers.length;
		int start = 0;
		int end = numbers[length - 1] - numbers[0];
		int answer = Integer.MAX_VALUE;

		while (start <= end) {
			int mid = (start + end) / 2;
			if (findMaxMinFromDifference(mat, numbers, mid, n)) {
				answer = mid; // 경로가 존재하니까 일단 저장
				end = mid - 1; // 더 줄여보자
			} else {
				start = mid + 1;
			}
		}

		return answer;
	}

	private static boolean findMaxMinFromDifference(int mat[][], int[] numbers, int diff, int n) { // 투 포인터
		int length = numbers.length;

		int start = 0;
		int end = 0;

		while (start < length && end < length) {
			if (numbers[end] - numbers[start] > diff) {
				start++;
			} else {

				if (bfs(mat, numbers[end], numbers[start], n)) {
					return true;
				}
				end++;
			}
		}

		return false;
	}

	// 최댓값과 최솟값의 차이가 min 보다 클 경우 false 리턴
	public static boolean bfs(int[][] mat, int max, int min, int n) { // bfs

		if (!isValuePossible(mat[0][0], max, min)) {
			return false;
		}

		Queue<Route> queue = new LinkedList<Route>();
		queue.add(new Route(0, 0));
		boolean[][] isVisited = new boolean[n][n];
		isVisited[0][0] = true;

		while (!queue.isEmpty()) {
			Route route = queue.poll();

			if (route.row == n - 1 && route.col == n - 1) {
				return true;
			}

			for (int i = 0; i < 4; i++) {
				int newRow = route.row + dr[i];
				int newCol = route.col + dc[i];

				if (isBoundary(newRow, newCol, n) && !isVisited[newRow][newCol]
						&& isValuePossible(mat[newRow][newCol], max, min)) {
					Route newRoute = new Route(newRow, newCol);
					isVisited[newRow][newCol] = true;

					queue.add(newRoute);
				}
			}
		}
		return false;
	}

	public static boolean isValuePossible(int value, int max, int min) {
		if (value < min) {
			return false;
		}
		if (value > max) {
			return false;
		}
		return true;
	}

	public static boolean isBoundary(int row, int col, int n) {
		if (row < 0) {
			return false;
		}
		if (row >= n) {
			return false;
		}
		if (col < 0) {
			return false;
		}
		if (col >= n) {
			return false;
		}
		return true;
	}
}

class Route {
	int row;
	int col;

	public Route(int row, int col) {
		this.row = row;
		this.col = col;
	}
}

 

생각해보니 굳이 이분탐색으로 범위를 줄여서 또 두 포인터로 각각 최대/최소 원소를 구하는 것은 연산이 중복되는 느낌이 들었다..ㅋㅋㅋ

따라서 이분탐색 부분은 제외하고 두 포인터와 bfs를 이용한 풀이로 다시 고쳐보았다.

추가적으로 isVisited의 경우 함수 내에서 계속 새로 할당할 경우 시간이 더 걸릴 수 있으므로 재사용하는 부분을 추가했다.

import java.util.*;

public class Main {
	public static int dr[] = { 0, 0, 1, -1 };
	public static int dc[] = { 1, -1, 0, 0 };
	public static boolean isVisited[][];

	public static void main(String[] args) {
		Scanner in = new Scanner(System.in);
		int n = in.nextInt();
		int mat[][] = new int[n][n];
		isVisited = new boolean[n][n];

		TreeSet<Integer> set = new TreeSet<Integer>();
		for (int i = 0; i < n; i++) {
			for (int j = 0; j < n; j++) {
				mat[i][j] = in.nextInt();
				set.add(mat[i][j]);
			}
		}

		int[] numbers = set.stream().mapToInt(i -> i).toArray();
		System.out.println(findMaxMin(mat, numbers, n));
	}

	private static int findMaxMin(int mat[][], int[] numbers, int n) { // 투 포인터로 max, min 정하기
		int length = numbers.length;

		int start = 0;
		int end = 0;

		int answer = Integer.MAX_VALUE;

		while (start < length && end < length) {
			int diff = numbers[end] - numbers[start];
			if (bfs(mat, numbers[end], numbers[start], n)) {
				answer = Math.min(answer, diff); // 가능한 경로이므로 일단 저장

				start++; // 더 줄여보자
			} else {
				end++; // 불가능한 경로이므로 diff 범위를 늘리자
			}
		}

		return answer;
	}

	public static boolean bfs(int[][] mat, int max, int min, int n) { // bfs 가능한 경로 탐색
		if (!isPossible(0, 0, n, max, min, mat)) {
			return false;
		}

		clearMatrix(isVisited, n);

		Queue<Route> queue = new LinkedList<Route>();
		queue.add(new Route(0, 0));
		isVisited[0][0] = true;

		while (!queue.isEmpty()) {
			Route route = queue.poll();

			if (route.row == n - 1 && route.col == n - 1) {
				return true;
			}

			for (int i = 0; i < 4; i++) {
				int newRow = route.row + dr[i];
				int newCol = route.col + dc[i];

				if (isPossible(newRow, newCol, n, max, min, mat) && !isVisited[newRow][newCol]) {
					Route newRoute = new Route(newRow, newCol);
					isVisited[newRow][newCol] = true;

					queue.add(newRoute);
				}
			}
		}
		return false;
	}

	public static void clearMatrix(boolean[][] isVisited, int n) {
		for (int i = 0; i < n; i++) {
			for (int j = 0; j < n; j++) {
				isVisited[i][j] = false;
			}
		}
	}

	public static boolean isPossible(int row, int col, int n, int max, int min, int[][] mat) {
		// 바운더리 안에 존재하며, [min, max]인 값임을 확인
		if (row < 0) {
			return false;
		}
		if (row >= n) {
			return false;
		}
		if (col < 0) {
			return false;
		}
		if (col >= n) {
			return false;
		}
		if (mat[row][col] < min) {
			return false;
		}
		if (mat[row][col] > max) {
			return false;
		}

		return true;
	}
}

class Route {
	int row;
	int col;

	public Route(int row, int col) {
		this.row = row;
		this.col = col;
	}

	@Override
	public String toString() {
		return "(" + row + ", " + col + ")";
	}
}

 

 

 

 

'알고리즘 공부 > boj' 카테고리의 다른 글

boj 1005: ACM Craft  (0) 2021.01.20
boj 1949: 우수 마을  (0) 2021.01.19
boj 3745: 오름세  (0) 2021.01.15
boj 1091: 카드 섞기  (0) 2021.01.11
boj 1153: 네 개의 소수  (0) 2021.01.10

이 문제에서 주의해야할 점은 아래 2가지이다.

  • EOF 처리
  • 최장부분증가수열을 빠르게 구하기
    • 완전탐색 => O(2^N)

 

1차 시도 - `동적 계획법`을 사용하여 문제를 풀어보았다. 결과는 50%에서 시간초과.

=> O(N^2), N ≤ 100000이므로 1초안에 통과될 수 없다. 아마 10초정도 걸릴것임...ㅠㅠ

 

dp[n]: n번째 수를 마지막으로 하는 최장증가부분수열로 정의했다.

import java.util.*;

public class Main {

	public static void main(String[] args) {
		Scanner in = new Scanner(System.in);
		while (in.hasNextInt()) {

			int n = in.nextInt();
			int[] stock = new int[n];
			int[] dp = new int[n];
			int max = 0;
			for (int i = 0; i < n; i++) {
				stock[i] = in.nextInt();
			}

			dp[0] = 1;

			for (int i = 1; i < n; i++) {
				dp[i] = 1;
				for (int j = 0; j < i; j++) {
					if (stock[i] > stock[j]) {
						dp[i] = Math.max(dp[j], dp[j] + 1);
					}
				}
				max = Math.max(max, dp[i]);
			}
			System.out.println(max);
		}
	}
}

 

 

2차 시도 - N ≤ 100000이므로 1초안에 통과하려면 시간복잡도가 적어도 NlogN을 되어야 한다. => `이분탐색`을 이용한다

stock 수열을 처음부터 보면서

1. dp의 끝 값과 비교했을 때 마지막 값보다 큰 경우 dp의 마지막에 바로 삽입

2. dp의 끝 값과 비교했을 때 마지막 값보다 작거나 같은 경우 이분탐색을 이용하여 LIS를 유지하기 위한 위치에 수를 삽입하도록 한다.

https://www.acmicpc.net/problem/3745 예제

 

 

 

 

 

 

stock[0]을 dp 리스트에 넣는다.

 

 

stock[1]이 어디에 삽입될 수 있는지 인덱스를 이분탐색을 이용하여 구한다. (index=0)

 

 

stock[2]가 어디에 삽입될 수 있는지 인덱스를 이분탐색을 이용하여 구한다. (index=0)

 

 

stock[3]은 1보다 크므로 바로 삽입

 

 

stock[4]는 4보다 크므로 바로 삽입

 

 

 

stock[5]가 어디에 삽입될 수 있는지 인덱스를 이분탐색을 이용하여 구한다. (index=1)

 

 

 

 

 

 

예제에서 볼 수 있듯이 최종 dp 수열은 진짜 최장 증가 부분 수열을 이루는 요소와는 상관 없으며, lis의 길이만 연관이 있다는 점이 중요하다

위 알고리즘을 적용하여 코드를 짜 보면 아래와 같다.

import java.util.*;

public class Main {

	public static void main(String[] args) {
		Scanner in = new Scanner(System.in);
		while (in.hasNextInt()) {

			int n = in.nextInt();
			int[] stock = new int[n];
			int[] dp = new int[n];
			for (int i = 0; i < n; i++) {
				stock[i] = in.nextInt();
			}

			dp[0] = stock[0];
			int lastIndex = 0;

			for (int i = 1; i < n; i++) {
				if (dp[lastIndex] < stock[i]) {
					lastIndex++;
					dp[lastIndex] = stock[i];
				} else {
					int index = findIndex(dp, stock[i], lastIndex);
					dp[index] = stock[i];
				}
			}
			System.out.println(lastIndex + 1);
		}
	}

	public static int findIndex(int[] dp, int num, int lastIndex) {
		int left = 0;
		int right = lastIndex;

		while (left < right) {
			int mid = (left + right) / 2;
			if (dp[mid] == num) {
				return mid;
			}

			if (dp[mid] > num) {
				right = mid;
			} else {
				left = mid + 1;
			}
		}

		return right;
	}
}

 

 

다른 방법으로는 `segment tree`를 사용하는 방법도 있다. segment tree를 사용하여 lis 길이를 구하는 방법은 아래와 같다.

1. 세그먼트 트리를 모두 0으로 초기화한다. , (stock[i], i) 객체를 만든 후 stock[i] 값에 대해 오름차순으로 정렬한다.

2. (stock[i], i)를 순회하면서 stock[i]에 대해 구간 [0, i]에서 최댓값을 구하고, 그 최대값+1을 세그먼트 트리의 인덱스 i인 리프 노드 값으로 업데이트한다. => i에 대해 구간 [0, i]에 지금까지 존재하는 LIS 길이+1 은 결국 stock[i]으로 끝나는 LIS길이와 같다.

3. 정렬된 객체를 순회하면서 LIS의 max 값을 찾는다.

 

 

 

가장 먼저 stock[i]=1인 i=2를 방문하게 된다.

먼저 구간 [0, 2]의 최댓값은 0이므로 1로 끝나는 LIS 길이는 1이고,

그 1 값을 인덱스 2에 업데이트 해 준다.

 

 

 

 

 

 

 

 

 

 

 

 

 

 

그 다음 stock[i]=2인 i=1를 방문하게 된다.

마찬가지로 [0, 1]의 최댓값은 0이므로 인덱스 1에 업데이트 해준다.

 

이때, 기존 LIS 결과가 증가하지는 않는다.

일단 이후 값이 언제 증가되는지 좀 더 보기로 하자.

 

 

 

 

 

 

 

 

 

 

 

 

그 다음 stock[i]=3인 i=5를 방문하게 되는데,

[0, 5]의 최댓값은 1이므로 인덱스 5에 2를 업데이트 해준다.

 

즉, 새로 보는 원소가 기존의 LIS 길이를 증가시키려면 

그 원소가 기존의 LIS보다 뒤에 나타나야 한다.

=> 이를 확인하는 것이 결국 구간 [0, i]의 최댓값을 보는 것이다.

이렇게 세그먼트 트리를 이용하여 stock[i]의 위치에 i번째 수를 마지막 원소로 가지는 lis의 길이를 업데이트함으로써 lis의 가장 긴 길이를 구할 수 있다.

 

 

 

 

 

 

 

 

마찬가지로 stock[i]=4인 i=3를 방문하게 된다.

[0, 3]의 최댓값은 1이므로 인덱스 3에 1+1=2를 업데이트 해준다.

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

stock[i]=5인 i=0를 방문하게 된다.

[0, 0]의 최댓값은 0이므로 인덱스 0에 0+1=1을 업데이트 해준다.

 

 

 

 

 

 

 

 

 

 

 

 

 

마지막으로 stock[i]=5인 i=4를 방문하게 된다.

[0, 4]의 최댓값은 2이므로 인덱스 4에 2+1=3을 업데이트 해준다

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

최종 구현을 직접 코드로는 안해봤지만... 나중에 업데이트 해 볼 생각히다

 

'알고리즘 공부 > boj' 카테고리의 다른 글

boj 1949: 우수 마을  (0) 2021.01.19
boj 1981: 배열에서 이동  (0) 2021.01.17
boj 1091: 카드 섞기  (0) 2021.01.11
boj 1153: 네 개의 소수  (0) 2021.01.10
boj 17182: 우주 탐사선  (0) 2021.01.10
  • 첫째 줄에 몇 번 섞어야 하는지 출력한다. 만약, 섞어도 섞어도 카드를 해당하는 플레이어에게 줄 수 없다면, -1을 출력한다.
    • -1을 출력하는 기준을 무엇으로 잡을 것인가? => 카드를 섞으면 언젠가 원래 수열과 똑같이 돌아오는 사이클이 존재할 것이다.
import java.util.*;

public class Main {
	public static void main(String[] args) {
		Scanner in = new Scanner(System.in);
		int n = in.nextInt();
		int destination[] = new int[n];
		int shuffle[] = new int[n];
		int cards[] = new int[n];

		for (int i = 0; i < n; i++) {
			destination[i] = in.nextInt();
			cards[i] = destination[i];
		}
		for (int i = 0; i < n; i++) {
			shuffle[i] = in.nextInt();
		}

		int index = 0;
		while (true) {
			if (isPossible(cards)) {
				break;
			}

			shuffleCards(cards, shuffle);
			index++;

			if (isSame(destination, cards)) {
				index = -1;
				break;
			}
		}
		System.out.println(index);
	}

	private static void shuffleCards(int[] destination, int[] shuffle) {
		int length = destination.length;
		int newDestination[] = new int[length];

		for (int i = 0; i < length; i++) {
			newDestination[shuffle[i]] = destination[i];
		}
		for (int i = 0; i < length; i++) {
			destination[i] = newDestination[i];
		}
		newDestination = null;
	}

	private static boolean isPossible(int[] destination) {
		for (int i = 0; i < destination.length; i++) {
			if (destination[i] != i % 3) {
				return false;
			}
		}
		return true;
	}

	private static boolean isSame(int[] destination, int[] cards) {
		for (int i = 0; i < destination.length; i++) {
			if (destination[i] != cards[i]) {
				return false;
			}
		}
		return true;
	}
}

'알고리즘 공부 > boj' 카테고리의 다른 글

boj 1981: 배열에서 이동  (0) 2021.01.17
boj 3745: 오름세  (0) 2021.01.15
boj 1153: 네 개의 소수  (0) 2021.01.10
boj 17182: 우주 탐사선  (0) 2021.01.10
boj 1655: 가운데를 말해요  (0) 2021.01.03

이 문제는 미리 1,000,000이하의 소수를 구해두고 bruteforce로 네 개의 소수를 구하다가 시간초과가 발생했는데,

이를 최적화 하는 방법을 생각하지 못해서 결국 다른 블로그들의 풀이를 참고했다ㅠㅠ

골드 바흐의 추측 문제를 풀었었는데도 이러한 방향으로 아이디어를 전혀 떠올리지 못했음..

 

골드바흐의 추측 - 2보다 큰 짝수는 무조건 두개의 소수의 합으로 나타낼 수 있다

1. 미리 1,000,000이하의 소수를 구해둔다.

2. N이 홀수인 경우

  • 골드바흐의 추측을 적용하기 위해 이를 짝수로 만들어준다 - 가장 작은 홀수 소수인 3을 뺀다.
  • 나머지 짝수를 두개의 소수로 분리한다.

2. N이 짝수인 경우

  • 골드바흐의 추측을 적용하기 위해 그대로 짝수로 만들어준다 - 가장 작은 짝수 소수인 2을 뺀다.
  • 나머지 짝수를 두개의 소수로 분리한다.
import java.util.*;

public class Main {
	public static int max = 1000000;

	public static void main(String[] args) {
		Scanner in = new Scanner(System.in);

		int n = in.nextInt();
		boolean[] isPrime = new boolean[n + 1];
		calcPrimes(isPrime);

		if (n < 8) {
			System.out.println(-1);
		} else {
			if (n % 2 == 0) {
				System.out.print("2 2 ");
				n -= 4;
			} else {
				System.out.print("2 3 ");
				n -= 5;
			}

			for (int i = 0; i <= n; i++) {
				if (isPrime[i] && isPrime[n - i]) {
					System.out.println(i + " " + (n - i));
					break;
				}
			}
		}
	}

	public static void calcPrimes(boolean[] isPrime) {
		Arrays.fill(isPrime, true);
		isPrime[0] = false;
		isPrime[1] = false;

		int length = isPrime.length;
		for (int i = 2; i < length; i++) {
			int index = 2;
			while (true) {
				if (index * i >= length) {
					break;
				}

				isPrime[index * i] = false;
				index++;
			}
		}
	}

	public static void print(boolean[] isPrime) {
		for (int i = 0; i < isPrime.length; i++) {
			System.out.println(i + " " + isPrime[i]);
		}
	}

}

'알고리즘 공부 > boj' 카테고리의 다른 글

boj 3745: 오름세  (0) 2021.01.15
boj 1091: 카드 섞기  (0) 2021.01.11
boj 17182: 우주 탐사선  (0) 2021.01.10
boj 1655: 가운데를 말해요  (0) 2021.01.03
boj 15686: 치킨배달  (0) 2020.12.30

먼저 플로이드를 이용하여 최단 거리를 구해두고 dfs 탐색하도록 한다.

import java.util.*;

public class Main {
	static int answer = Integer.MAX_VALUE;

	public static void main(String[] args) throws Exception {
		Scanner in = new Scanner(System.in);
		int n = in.nextInt();// 행성의 개수
		int start = in.nextInt();// 시작점
		int[][] mat = new int[n][n];

		for (int i = 0; i < n; i++) {
			for (int j = 0; j < n; j++) {
				mat[i][j] = in.nextInt();
			}
		}

		for (int k = 0; k < n; k++) {
			for (int i = 0; i < n; i++) {
				for (int j = 0; j < n; j++) {
					mat[i][j] = Math.min(mat[i][j], mat[i][k] + mat[k][j]);
				}
			}
		}

		boolean[] visited = new boolean[n];
		visited[start] = true;
		dfs(visited, start, 0, 0, n, mat);

		System.out.println(answer);
	}

	public static void dfs(boolean[] isVisited, int temp, int sum, int depth, int n, int mat[][]) {
		if (depth == n - 1) {
			answer = Math.min(answer, sum);
			return;
		}

		for (int i = 0; i < n; i++) {
			if (!isVisited[i]) {
				isVisited[i] = true;
				dfs(isVisited, i, sum + mat[temp][i], depth + 1, n, mat);
				isVisited[i] = false;
			}
		}
	}

}

'알고리즘 공부 > boj' 카테고리의 다른 글

boj 1091: 카드 섞기  (0) 2021.01.11
boj 1153: 네 개의 소수  (0) 2021.01.10
boj 1655: 가운데를 말해요  (0) 2021.01.03
boj 15686: 치킨배달  (0) 2020.12.30
boj 1915: 가장 큰 정사각형  (0) 2020.12.24

시간초과를 해결하기 위해 사용

  • BufferdReader
  • StringBuilder
import java.util.*;
import java.io.*;

public class Main {
	public static void main(String[] args) throws Exception {
		PriorityQueue<Integer> maxQueue = new PriorityQueue<>();
		PriorityQueue<Integer> minQueue = new PriorityQueue<>((o1, o2) -> o2.compareTo(o1));

		StringBuilder sb = new StringBuilder("");
		BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
		int N = Integer.parseInt(br.readLine());
		for (int i = 0; i < N; i++) {
			int num = Integer.parseInt(br.readLine());
			maxQueue.add(num);
			if ((maxQueue.size() + minQueue.size()) % 2 != 0) {
				minQueue.add(maxQueue.poll());
			} else {
				if (minQueue.peek() > num) {
					maxQueue.add(minQueue.poll());
					minQueue.add(maxQueue.poll());
				}
			}
			sb.append(minQueue.peek() + "\n");
		}

		System.out.println(sb);
	}
}

'알고리즘 공부 > boj' 카테고리의 다른 글

boj 1153: 네 개의 소수  (0) 2021.01.10
boj 17182: 우주 탐사선  (0) 2021.01.10
boj 15686: 치킨배달  (0) 2020.12.30
boj 1915: 가장 큰 정사각형  (0) 2020.12.24
boj 10253: 헨리  (0) 2020.12.24
import java.util.*;

public class Main {
	public static final int[] dr = { -1, 0, 0, 1 };
	public static final int[] dc = { 0, -1, 1, 0 };

	public static final int SPACE = 0;
	public static final int HOME = 1;
	public static final int CHICKEN = 2;

	public static int min = Integer.MAX_VALUE;

	public static void main(String[] args) {
		Scanner in = new Scanner(System.in);
		int size = in.nextInt();
		int chickenNum = in.nextInt();

		int mat[][] = new int[size][size];
		ArrayList<Point> chickens = new ArrayList<Point>();
		ArrayList<Point> homes = new ArrayList<Point>();

		for (int i = 0; i < size; i++) {
			for (int j = 0; j < size; j++) {
				int position = in.nextInt();

				if (position == CHICKEN) {
					chickens.add(new Point(i, j));
				} else if (position == HOME) {
					homes.add(new Point(i, j));
				}
			}
		}

		for (int i = 0; i < chickens.size(); i++) {
			boolean check[] = new boolean[chickens.size()];
			check[i] = true;
			findAll(mat, homes, chickens, i, 1, chickenNum, check);
		}

		System.out.println(min);
	}

	public static void findAll(int mat[][], ArrayList<Point> homes, ArrayList<Point> chickens, int index, int num,
			int chickenNum, boolean[] check) {
		if (num == chickenNum) {
			min = Math.min(min, calcChickenDistance(mat, homes, chickens, check));
			return;
		}
		if (index == chickens.size()) {
			return;
		}

		for (int i = index + 1; i < chickens.size(); i++) {
			check[i] = true;
			findAll(mat, homes, chickens, i, num + 1, chickenNum, check);
			check[i] = false;
		}
	}

	public static int calcChickenDistance(int mat[][], ArrayList<Point> homes, ArrayList<Point> chickens,
			boolean[] check) {
		int distanceSum = 0;
		for (Point home : homes) {
			int distance = Integer.MAX_VALUE;
			for (int i = 0; i < check.length; i++) {
				if (check[i]) {
					Point chicken = chickens.get(i);
					distance = Math.min(distance, Math.abs(home.row - chicken.row) + Math.abs(home.col - chicken.col));
				}
			}
			distanceSum += distance;
		}

		return distanceSum;
	}
}

class Point {
	int row;
	int col;

	public Point(int row, int col) {
		this.row = row;
		this.col = col;
	}
}

'알고리즘 공부 > boj' 카테고리의 다른 글

boj 17182: 우주 탐사선  (0) 2021.01.10
boj 1655: 가운데를 말해요  (0) 2021.01.03
boj 1915: 가장 큰 정사각형  (0) 2020.12.24
boj 10253: 헨리  (0) 2020.12.24
boj 1520: 내리막길  (0) 2020.12.15

1 ≤ n, m ≤ 1,000 이므로 브루트포스로 다 구해본다면 O(N^2M^2)로 시간 제한에 걸릴 것이다.

array를 무조건 한 번은 봐야하기 때문에 O(NM) * ???가 2초 안에 실행 되어야 한다.

 

DP로 풀어볼 수 있는 방법을 생각해 보자

dp[i][j]: (i,j)를 오른쪽 아래로 포함한 가장 크게 만들 수 있는 정사각형의 한 변 길이로 잡고, mat[i][j]==1일때 dp를 업데이트 한다.

import java.util.*;

public class Main {
	public static void main(String[] args) {
		Scanner in = new Scanner(System.in);
		int row = in.nextInt();
		int col = in.nextInt();
		int mat[][] = new int[row][col];
		int dp[][] = new int[row][col];
		int maxLength = 0;

		for (int i = 0; i < row; i++) {
			String rowInput = in.next();
			int j = 0;
			for (char ch : rowInput.toCharArray()) {
				mat[i][j] = ch - '0';
				dp[i][j] = ch - '0';
				maxLength = ch - '0' > 0 ? 1 : 0;
				j++;
			}
		}

		for (int i = 1; i < row; i++) {
			for (int j = 1; j < col; j++) {
				if (mat[i][j] != 0) {
					dp[i][j] = findMinValueBetweenThree(dp[i - 1][j - 1], dp[i - 1][j], dp[i][j - 1]) + 1;
					maxLength = Math.max(maxLength, dp[i][j]);
				}
			}
		}
		System.out.println(maxLength * maxLength);
	}

	public static int findMinValueBetweenThree(int a, int b, int c) {
		return Math.min(a, Math.min(b, c));
	}
}

 

'알고리즘 공부 > boj' 카테고리의 다른 글

boj 1655: 가운데를 말해요  (0) 2021.01.03
boj 15686: 치킨배달  (0) 2020.12.30
boj 10253: 헨리  (0) 2020.12.24
boj 1520: 내리막길  (0) 2020.12.15
boj 11066: 파일 합치기  (0) 2020.07.21

+ Recent posts