문제 조건

  • 1 ≤ 신이 좋아하는 문자열의 길이 ≤ 5
  • 1 ≤ K ≤ 1,000, K는 자연수이다.

 

처음에는 문자열 길이만 보고 거의 완탐으로 문제를 풀었는데, 시간 초과가 났다

DP인가 했지만 이미 지나 왔던 칸들을 다시 방문하는 것은 허용한다고 했기 때문에 불가능 하고,

갈 수 있는 방향을 모두 탐색하는 대신 map으로 다음 문자열과 같은 곳만 탐색하도록 하는 방법을 사용했다.

이를 적용한 `틀린` 코드는 아래와 같다. => 이렇게 풀면 최악일 때 10* 10 * 1000 * 5^8 이 나온다

import java.util.*;

public class Main {

	private static int dr[] = { -1, -1, 0, 1, 1, 1, 0, -1 };
	private static int dc[] = { 0, -1, -1, -1, 0, 1, 1, 1 };

	private static int sum = 0;

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

		int row = in.nextInt();
		int col = in.nextInt();
		int testcase = in.nextInt();
		char[][] alphabets = new char[row + 1][col + 1];
		HashMap<Character, HashSet<Position>> map[][] = new HashMap[row + 1][col + 1];
		for (int i = 1; i <= row; i++) {
			String rowInput = in.next();
			for (int j = 1; j <= col; j++) {
				alphabets[i][j] = rowInput.charAt(j - 1);
				map[i][j] = new HashMap<Character, HashSet<Position>>();
			}
		}

		for (int i = 1; i <= row; i++) {
			for (int j = 1; j <= col; j++) {
				for (int d = 0; d < 8; d++) {
					int newRow = i + dr[d];
					int newCol = j + dc[d];

					if (newRow < 1) {
						newRow = row;
					}
					if (newCol < 1) {
						newCol = col;
					}
					if (newRow > row) {
						newRow = 1;
					}
					if (newCol > col) {
						newCol = 1;
					}

					char ch = alphabets[newRow][newCol];

					if (map[i][j] == null) {
						map[i][j] = new HashMap<Character, HashSet<Position>>();
					}
					if (!map[i][j].containsKey(ch)) {
						map[i][j].put(ch, new HashSet<>());
					}
					map[i][j].get(ch).add(new Position(newRow, newCol));
				}
			}
		}

		for (int t = 0; t < testcase; t++) {
			char[] favorite = in.next().toCharArray();
			int length = favorite.length;
			sum = 0;

			for (int i = 1; i <= row; i++) {
				for (int j = 1; j <= col; j++) {
					if (favorite[0] == alphabets[i][j]) {
						findAll(1, i, j, favorite, length, row, col, alphabets, map);
					}
				}
			}

			System.out.println(sum);
		}
	}

	private static void findAll(int index, int row, int col, char[] target, int targetLength, int maxRow, int maxCol,
			char[][] alphabets, HashMap<Character, HashSet<Position>> map[][]) {
		if (index == targetLength) {
			sum++;
			return;
		}

		HashSet<Position> set = map[row][col].get(target[index]);
		if (set != null) {

			for (Position p : set) {
				int newRow = p.row;
				int newCol = p.col;

				findAll(index + 1, newRow, newCol, target, targetLength, maxRow, maxCol, alphabets, map);
			}
		}
	}
}

class Position {
	int row, col;

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

 

 

 

그래서 어차피 완전 탐색은 한 번은 꼭 해야 할텐데 방문했을 때 생긴 문자열의 수를 각각 구해서 저장한 뒤,

문자열을 입력받을 때마다 바로 리턴하는 방식으로 바꾸기로 했다. 이렇게 될 경우 시간 복잡도는 O(10* 10 * 5^8) 으로 줄어들게 된다.

import java.io.*;
import java.util.*;

public class Main {

	private static final int dr[] = { -1, -1, 0, 1, 1, 1, 0, -1 };
	private static final int dc[] = { 0, -1, -1, -1, 0, 1, 1, 1 };

	private static final int MAX_LENGTH = 5;

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

		int row = Integer.parseInt(st.nextToken());
		int col = Integer.parseInt(st.nextToken());
		int testcase = Integer.parseInt(st.nextToken());
		char[][] alphabets = new char[row + 1][col + 1];
		HashMap<String, Integer> map = new HashMap<>();
		for (int i = 1; i <= row; i++) {
			String rowInput = br.readLine();
			for (int j = 1; j <= col; j++) {
				alphabets[i][j] = rowInput.charAt(j - 1);
			}
		}

		for (int i = 1; i <= row; i++) {
			for (int j = 1; j <= col; j++) {
				String createdString = Character.toString(alphabets[i][j]);
				map.put(createdString, map.getOrDefault(createdString, 0) + 1);
				findAll(1, i, j, row, col, map, createdString, alphabets);
			}
		}

		for (int t = 0; t < testcase; t++) {
			String favorite = br.readLine();
			System.out.println(map.getOrDefault(favorite, 0));
		}
	}

	private static void findAll(int index, int row, int col, int maxRow, int maxCol, HashMap<String, Integer> map,
			String createdString, char[][] alphabets) {
		if (index == MAX_LENGTH) {
			return;
		}

		for (int d = 0; d < 8; d++) {
			int newRow = row + dr[d];
			int newCol = col + dc[d];

			if (newRow < 1) {
				newRow = maxRow;
			}
			if (newCol < 1) {
				newCol = maxCol;
			}
			if (newRow > maxRow) {
				newRow = 1;
			}
			if (newCol > maxCol) {
				newCol = 1;
			}

			String newCreatedString = createdString + alphabets[newRow][newCol];
			map.put(newCreatedString, map.getOrDefault(newCreatedString, 0) + 1);
			findAll(index + 1, newRow, newCol, maxRow, maxCol, map, newCreatedString, alphabets);
		}
	}
}

 

 

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

boj 2631: 줄세우기  (0) 2021.04.01
boj 20165: 인내의 도미노 장인 호석  (0) 2021.03.24
boj 20164: 홀수 홀릭 호석  (0) 2021.03.24
boj 11663: 선분 위의 점  (0) 2021.03.17
boj 19637: IF문 좀 대신 써줘  (0) 2021.03.17

치즈는 4변 중에서 적어도 2변 이상이 실내온도의 공기와 접촉하면 녹는다.

이 때, dfs를 돌며 바로바로 치즈를 녹이는 식으로 문제를 풀면 안되고, 미리 어떤 치즈가 녹을지 체크를 한 뒤 해당 체크 부분만 녹이도록 해야 한다.

풀이는 아래와 같다.

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 m = in.nextInt();
		int mat[][] = new int[n][m];

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

		int time = 0;
		while (true) {
			boolean isVisited[][] = new boolean[n][m];
			boolean isMelted = false;

			dfs(0, 0, n, m, mat, isVisited);
			for (int i = 0; i < n; i++) {
				for (int j = 0; j < m; j++) {
					if (mat[i][j] == 1 && meltCheese(i, j, n, m, mat)) {
						isMelted = true;
					}
				}
			}

			if (!isMelted) {
				break;
			}
			time++;
		}
		System.out.println(time);
	}

	private static void dfs(int r, int c, int n, int m, int[][] mat, boolean[][] isVisited) {
		mat[r][c] = -1;
		isVisited[r][c] = true;
		for (int i = 0; i < 4; i++) {
			int row = r + dr[i];
			int col = c + dc[i];
			if (isBoundary(row, col, n, m) && mat[row][col] != 1 && !isVisited[row][col]) {
				dfs(row, col, n, m, mat, isVisited);
			}
		}
	}

	private static boolean meltCheese(int r, int c, int n, int m, int mat[][]) {
		int airs = 0;
		for (int i = 0; i < 4; i++) {
			int row = r + dr[i];
			int col = c + dc[i];
			if (isBoundary(row, col, n, m) && mat[row][col] == -1) {
				airs++;
			}
		}
		if (airs >= 2) {
			mat[r][c] = 0;
			return true;
		}
		return false;

	}

	private static boolean isBoundary(int row, int col, int maxRow, int maxCol) {
		if (row < 0 || col < 0) {
			return false;
		}
		if (row >= maxRow) {
			return false;
		}
		if (col >= maxCol) {
			return false;
		}
		return true;
	}
}

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

boj 1789: 수들의 합  (1) 2021.03.15
boj 1339: 단어 수학  (0) 2021.02.14
boj 1766: 문제집  (0) 2021.02.12
boj 1504:특정한 최단경로  (0) 2021.02.07
boj 11812: K진 트리  (0) 2021.02.07

먼저 플로이드를 이용하여 최단 거리를 구해두고 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

1. 가장 높은 위치를 찾아서 큐에 넣는다

2. 큐에 넣은 위치를 시작점으로 하는 dfs를 돌려 등산로 길이 중 max값을 찾도록 한다.

   - dfs를 돌릴때에는 공사를 하는 경우/ 안하는 경우를 나눈다.

   - 공사를 하는 경우에는 최소 값만 깎도록 해야 선택 폭이 넓어짐

import java.util.*;
class Solution {
	public static int dr[] = { 0, 1, 0, -1 };
	public static int dc[] = { 1, 0, -1, 0 };
	public static int maxAnswer;

	public static void main(String args[]) {
		Scanner in = new Scanner(System.in);
		int test = in.nextInt();
		for (int t = 1; t <= test; t++) {
			int n = in.nextInt();
			int depth = in.nextInt();
			int[][] mat = new int[n][n];
			int max = 0;
			maxAnswer = 0;

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

			Queue<Position> queue = new LinkedList<Position>();
			for (int i = 0; i < n; i++) {
				for (int j = 0; j < n; j++) {
					if (mat[i][j] == max) {
						queue.add(new Position(i, j));
					}
				}
			}

			while (!queue.isEmpty()) {
				boolean[][] isVisited = new boolean[n][n];

				Position now = queue.poll();

				isVisited[now.row][now.col] = true;
				dfs(now.row, now.col, depth, 1, 0, mat, isVisited, n);
			}
			System.out.println("#" + t + " " + maxAnswer);
		}

	}

	public static void dfs(int row, int col, int depth, int length, int minus, int[][] mat, boolean[][] isVisited,
			int n) {
		for (int i = 0; i < 4; i++) {
			maxAnswer = Math.max(maxAnswer, length);

			int newRow = row + dr[i];
			int newCol = col + dc[i];

			if (isBoundary(newRow, newCol, n) && !isVisited[newRow][newCol]) {
				// 깎는경우
				if (mat[row][col] <= mat[newRow][newCol] && mat[row][col] > mat[newRow][newCol] - depth) {
					isVisited[newRow][newCol] = true;
					dfs(newRow, newCol, 0, length + 1, mat[newRow][newCol] - mat[row][col] + 1, mat, isVisited, n);
					isVisited[newRow][newCol] = false;
				}
				// 안깎는경우
				else if (mat[row][col] - minus > mat[newRow][newCol]) {
					isVisited[newRow][newCol] = true;
					dfs(newRow, newCol, depth, length + 1, 0, mat, isVisited, n);
					isVisited[newRow][newCol] = false;
				}
			}
		}
	}

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

class Position {
	int row;
	int col;

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

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

SWEA 1248: 공통조상  (0) 2021.01.17
SWEA 3462: 선표의 축구 경기 예측  (0) 2021.01.10
SWEA 1267: 작업순서  (0) 2021.01.03
SWEA 5653: 줄기세포 배양  (0) 2021.01.03
SWEA 5521: 상원이의 생일파티  (0) 2020.12.27

+ Recent posts