-
그리디&구현, DFS&BFSAlgorithm 2020. 9. 1. 21:52
그리디 & 구현
- 시각
import java.io.*; public class Main { public static void main(String[] args) throws IOException { BufferedReader br = new BufferedReader(new InputStreamReader(System.in)); /** * 구현 * 시각 * N시 59분 59초까지 3이 하나라도 포함되는 모든 경우의 수 */ int h = Integer.parseInt(br.readLine()); int cnt = 0; for (int i = 0; i <= h; i++) { for (int j = 0; j < 60; j++) { for (int k = 0; k < 60; k++) { if (check(i, j , k)) { cnt ++; } } } } System.out.println(cnt); } public static boolean check(int h, int m, int s) { return h % 10 == 3 || m / 10 == 3 || m % 10 == 3 || s / 10 == 3 || s % 10 == 3; } }
- 곱하기 혹은 더하기
import java.io.*; public class Main { public static void main(String[] args) throws IOException { BufferedReader br = new BufferedReader(new InputStreamReader(System.in)); // 곱하기 혹은 더하기 // S의 길이는 1 ~20 // 0~9의 수로 이루어져있음 // 가장 큰 수 구하기 String S = br.readLine(); long ans = S.charAt(0) - '0'; for (int i = 1; i < S.length(); i++) { if (S.charAt(i) - '0' <= 1) { ans += (S.charAt(i) - '0'); } else { ans *= (S.charAt(i) - '0'); } } System.out.println(ans); } }
- 좌표 이동하기
import java.util.*; public class Main { public static void main(String[] args) { Scanner sc = new Scanner(System.in); // N을 입력받기 int n = sc.nextInt(); sc.nextLine(); // 버퍼 비우기 String[] plans = sc.nextLine().split(" "); int x = 1, y = 1; // L, R, U, D에 따른 이동 방향 int[] dx = {0, 0, -1, 1}; int[] dy = {-1, 1, 0, 0}; char[] moveTypes = {'L', 'R', 'U', 'D'}; // 이동 계획을 하나씩 확인 for (int i = 0; i < plans.length; i++) { char plan = plans[i].charAt(0); // 이동 후 좌표 구하기 int nx = -1, ny = -1; for (int j = 0; j < 4; j++) { if (plan == moveTypes[j]) { nx = x + dx[j]; ny = y + dy[j]; } } // 공간을 벗어나는 경우 무시 if (nx < 1 || ny < 1 || nx > n || ny > n) continue; // 이동 수행 x = nx; y = ny; } System.out.println(x + " " + y); } }
DFS & BFS
그래프 탐색이란 ?
- 하나의 정점으로부터 시작하여 차례대로 모든 정점들을 한 번씩 방문하는 것
Ex) 특정 도시에서 다른 도시로 갈 수 있는지 없는지, 전자 회로에서 특정 단자와 단자가 서로 연결되어 있는지
- DFS
1. 미로를 탐색할 때 한 방향으로 갈 수 있을 때까지 계속 가다가 더 이상 갈 수 없게 되면 다시 가장 가까운 갈림길로 돌아와서 이곳으로부터 다른 방향으로 다시 탐색을 진행하는 방법과 유사함
2. 즉 넓게(wide) 탐색하기 전에 깊게(deep) 탐색함
3. 모든 노드를 방문하고자 하는 경우에 이 방법을 선택함
4. 깊이 우선 탐색(DFS)이 너비 우선 탐색(BFS)보다 좀 더 간단함
5. 검색 속도 자체는 너비 우선 탐색(BFS)에 비해서 느림
깊이 우선 탐색(DFS)의 특징
- 자기 자신을 호출하는 순환 알고리즘의 형태를 지님
- 이 알고리즘을 구현할 때 가장 큰 차이점은 그래프 탐색의 경우 어떤 노드를 방문했었는지 여부를 반드시 검사해야한다는 것 (이를 검사하지 않을 경우 무한루프에 빠질 위험이 있음)
깊이 우선 탐색(DFS)의 구현 방법
1. 순환 호출 이용
2. 명시적인 스택 사용
import java.util.ArrayList; /** * DFS 깊이 우선 탐색 * 그래프에서 깊은 부분을 우선적으로 탐색하는 알고리즘 * 스택 자료구조 (혹은 재귀 함수)를 이용, * 1. 탐색 시작 노드를 스택에 삽입하고 방문 처리 * 2. 스택 최상단 노드에 방문하지 않은 인접한 노드가 하나라도 있으면 * 그 노드를 스택에 넣고 방문처리 한다. * 3. 더 이상 2번의 과정을 수행할 수 없을 떄까지 반복 * */ public class DFS { public static boolean[] visited = new boolean[9]; // 방문처리했는지 확인하기 위한 배열 public static ArrayList<ArrayList<Integer>> graph = new ArrayList<ArrayList<Integer>>(); // 그래프 전체 // dfs 함수 정의 public static void dfs(int x) { // 현재 노드를 방문 처리 visited[x] = true; System.out.print(x + " "); // 현재 노드와 연결된 다른 노드를 재귀적으로 방문 for (int i = 0; i < graph.get(x).size(); i++) { int y = graph.get(x).get(i); if (!visited[y]) { dfs(y); } } } public static void main(String[] args) { // 그래프 초기화 for (int i = 0; i < 9; i++) { graph.add(new ArrayList<Integer>()); } // 노드 1에 연결된 노드 정보 저장 graph.get(1).add(2); graph.get(1).add(3); graph.get(1).add(8); // 노드 2에 연결된 노드 정보 저장 graph.get(2).add(1); graph.get(2).add(7); // 노드 3에 연결된 노드 정보 저장 graph.get(3).add(1); graph.get(3).add(4); graph.get(3).add(5); // 노드 4에 연결된 노드 정보 저장 graph.get(4).add(3); graph.get(4).add(5); // 노드 5에 연결된 노드 정보 저장 graph.get(5).add(3); graph.get(5).add(4); // 노드 6에 연결된 노드 정보 저장 graph.get(6).add(7); // 노드 7에 연결된 노드 정보 저장 graph.get(7).add(2); graph.get(7).add(6); graph.get(7).add(8); // 노드 8에 연결된 노드 정보 저장 graph.get(8).add(1); graph.get(8).add(7); dfs(1); } }
- BFS
1. 시작 정점으로부터 가까운 정점을 먼저 방문하고 멀리 떨어져 있는 정점을 나중에 방문하는 순회 방법
2. 즉 깊게(deep) 탐색하기 전에 넓게(wide) 탐색하는 것
3. 두 노드 사이의 최단 경로 혹은 임의의 경로를 찾고 싶을 때 이 방법을 선택함
너비 우선 탐색(BFS)의 특징
- BFS 는 재귀적으로 동작하지 않는다.
- 이 알고리즘을 구현할 때 가장 큰 차이점은 그래프 탐색의 경우 어떤 노드를 방문했었는지 여부를 반드시 검사해야한다는 것이다 이를 검사하지 않을 경우 무한 루프에 빠질 위험이 있다.
- BFS 는 방문한 노드들을 차례로 저장한 후 꺼낼 수 있는 자료 구조인 큐(Queue)를 사용함
- 즉 선입선출(FIFO) 원칙으로 탐색
너비 우선 탐색(BFS)의 구현방법
- 자료구조 큐 (Queue)를 이용
import java.util.ArrayList; import java.util.LinkedList; import java.util.Queue; /** * BFS 너비 우선 탐색 * 그래프에서 가까운 노드부터 우선적으로 탐색하는 알고리즘 * 큐 자료구조 이용, * 1. 탐색 시작 노드를 큐에 삽입하고 방문처리 * 2. 큐에서 노드를 꺼낸 뒤에 해당 노드의 인접 노드 중에서 * 방문하지 않은노드를 모두 큐에 삽입하고 방문 처리한다. * 3. 더 이상 2번의 과정을 수행할 수 없을때까지 반복 */ public class BFS { public static boolean[] visited = new boolean[9]; public static ArrayList<ArrayList<Integer>> graph = new ArrayList<ArrayList<Integer>>(); // BFS 함수 정의 public static void bfs(int start) { Queue<Integer> q = new LinkedList<>(); q.offer(start); // 현재 노드를 방문 처리 visited[start] = true; // 큐가 빌 때까지 반복 while (!q.isEmpty()) { // 큐에서 하나의 원소를 뽑아 출력 int x = q.poll(); System.out.print(x + " "); // 해당 원소와 연결된, 아직 방문하지 않은 원소들을 큐에 삽입 for (int i = 0; i < graph.get(x).size(); i++) { int y = graph.get(x).get(i); if (!visited[y]) { q.offer(y); visited[y] = true; } } } } public static void main(String[] args) { // 그래프 초기화 for (int i = 0; i < 9; i++) { graph.add(new ArrayList<Integer>()); } // 노드 1에 연결된 노드 정보 저장 graph.get(1).add(2); graph.get(1).add(3); graph.get(1).add(8); // 노드 2에 연결된 노드 정보 저장 graph.get(2).add(1); graph.get(2).add(7); // 노드 3에 연결된 노드 정보 저장 graph.get(3).add(1); graph.get(3).add(4); graph.get(3).add(5); // 노드 4에 연결된 노드 정보 저장 graph.get(4).add(3); graph.get(4).add(5); // 노드 5에 연결된 노드 정보 저장 graph.get(5).add(3); graph.get(5).add(4); // 노드 6에 연결된 노드 정보 저장 graph.get(6).add(7); // 노드 7에 연결된 노드 정보 저장 graph.get(7).add(2); graph.get(7).add(6); graph.get(7).add(8); // 노드 8에 연결된 노드 정보 저장 graph.get(8).add(1); graph.get(8).add(7); bfs(1); } }
- 음료수 채우기
import java.io.*; import java.util.StringTokenizer; /** * 음료수 얼려 먹기 * 첫 번째 줄에 얼음 틀의 세로길이 N, 가로길이 M / N,M : 1~1000 * 두 번째 줄부터 N+1 번째 줄까지 얼음틀의 형태 * 0 : 구멍이 뚫린 부분, 1 : 막힌 부분 * 한 번에 만들 수 있는 아이스크림의 개수 ? */ /** * DFS 활용 * 1. 특정한 지점의 주변의 상, 하, 좌, 우를 살펴본 뒤에 * 주변 지점 중에서 값이 '0'이면서 아직 방문하지 않은 지점이 있다면 해당 지점 방문 * 2. 방문한 지점에서 다시 상, 하, 좌, 우를 살펴보면서 방문을 진행하는 과정을 반복하면, * 연결된 모든 지점을 방문할 수 있다. * 3. 모든 노드에 대하여 1~2 번의 과정을 반복하며, 방문하지 않은 지점의 수를 카운트한다. */ public class Main { public static int n, m; public static int[][] graph = new int[1000][1000]; // dfs로 특정 노드를 방문하고 연결된 모든 노드들도 방문 public static boolean dfs(int x, int y) { // 주어진 범위를 벗어나는 경우에는 즉시 종료 if (x <= -1 || x >= n || y <= -1 || y >= m) { return false; } // 현재 노드를 아직 방문하지 않았다면 if (graph[x][y] == 0) { // 해당 노드 방문 처리 graph[x][y] = 1; // 상, 하, 좌, 우의 위치들도 모두 재귀적으로 호출 dfs(x - 1, y); dfs(x, y-1); dfs(x + 1, y); dfs(x, y + 1); return true; } return false; } public static void main(String[] args) throws IOException { BufferedReader br = new BufferedReader(new InputStreamReader(System.in)); StringTokenizer st = new StringTokenizer(br.readLine()); // n, m 입력 n = Integer.parseInt(st.nextToken()); // 세로 길이 m = Integer.parseInt(st.nextToken()); // 가로 길이 // 2차원 리스트의 맵 정보 입력 받기 for (int i = 0; i < n; i++) { st = new StringTokenizer(br.readLine()); for (int j = 0; j < m; j++) { graph[i][j] = Integer.parseInt(st.nextToken()); } } // 모든 노드(위치)에 대하여 음료수 채우기 int result = 0; for (int i = 0; i < n; i++) { for (int j = 0; j < m; j++) { // 현재 위치에서 dfs 수행 if (dfs(i, j)) { result += 1; } } } System.out.println(result); } }
- 미로 탈출
import java.util.LinkedList; import java.util.Queue; import java.util.Scanner; /** * 미로 탈출 * 첫째 줄에 두 정수 N, M 4~200 * 다음 N개의 줄에는 각각 M개의 정수 (0, 1)의 미로 정보가 주어진다. * 또한 시작과 마지막 칸은 항상 1이다. * 괴물이 있는 부분 0, 괴물이 없는 부분 1 * 한 번에 한 칸씩 이동, 시작칸, 마지막칸 포함 * 탈출하기 위해 움직여야 하는 최소 칸의 개수 ? */ class Node { private int index; private int distance; public Node(int index, int distance) { this.index = index; this.distance = distance; } public int getIndex() { return index; } public int getDistance() { return distance; } } public class Main { public static int n, m; public static int[][] graph = new int[201][201]; // 이동할 네 가지 방향 정의 (상, 하, 좌, 우) public static int dx[] = {-1, 1, 0, 0}; public static int dy[] = {0, 0, -1, 1}; public static int bfs(int x, int y) { // 큐 쓰기위해서 queue 라이브러리 사용 Queue<Node> q = new LinkedList<>(); q.offer(new Node(x, y)); // 큐에 노드 넣기 // 큐가 빌 때까지 반복 while (!q.isEmpty()) { Node node = q.poll(); // 꺼내기 x = node.getIndex(); y = node.getDistance(); // 현재 위치에서 4가지 방향으로의 위치 확인 for (int i = 0; i < 4; i++) { int nx = x + dx[i]; int ny = y + dy[i]; // 공간을 벗어난 경우 무시 if (nx < 0 || nx >= n || ny < 0 || ny >= m) { continue; } // 벽인 경우 무시 if (graph[nx][ny] == 0) { continue; } // 해당 노드를 처음 방문하는 경우에만 최단 거리 기록 if (graph[nx][ny] == 1) { graph[nx][ny] = graph[x][y] + 1; q.offer(new Node(nx, ny)); } } } // 가장 오른쪽 아래까지의 최단 거리 반환 return graph[n-1][m-1]; } public static void main(String[] args) { Scanner sc = new Scanner(System.in); // n, m 입력 n = sc.nextInt(); m = sc.nextInt(); sc.nextLine(); // 버퍼지우기 // 맵 정보 입력 받기 for (int i = 0; i < n; i++) { String str = sc.nextLine(); for (int j = 0; j < m; j++) { graph[i][j] = str.charAt(j) - '0'; } } // 결과 출력 System.out.println(bfs(0, 0)); } }
※참조
github.com/ndb796/python-for-coding-test
'Algorithm' 카테고리의 다른 글
다이나믹 프로그래밍 정리 (0) 2020.09.09 트리 정리 (0) 2020.09.07 LinkedList (0) 2020.08.31 EOF (End of File) (0) 2020.08.29 정렬 정리 (0) 2020.08.27