본문 바로가기
알고리즘/BAEKJOON

[백준] 1941 소문난 칠공주 (Java)

by kyeee2 2022. 4. 20.

[1941 소문난 칠공주]

난이도: 골드3

 

1941번: 소문난 칠공주

총 25명의 여학생들로 이루어진 여학생반은 5×5의 정사각형 격자 형태로 자리가 배치되었고, 얼마 지나지 않아 이다솜과 임도연이라는 두 학생이 두각을 나타내며 다른 학생들을 휘어잡기 시작

www.acmicpc.net

문제

입력

출력


[아이디어]

BFS와 백트래킹 그리고 조합을 사용하는 문제이다.

단순한 BFS를 사용하면 십자가모양을 만들어낼 수 없기 때문에 조합을 사용하여 먼저 7명을 선택해준다.

이 때, 5 x 5 로 학생들이 주어지기 때문에 0 ~ 24로 번호를 정하고 조합을 구하면 편하다.

n번 학생의 (행, 열)을 구하는 방법은 (n / 5, n % 5) 이므로 번호를 좌표로 변환하는 것은 크게 어렵지 않다.

7명을 모두 선택한 후에는 그 안에 '이다솜'파가 몇 명인지 먼저 세어보고 4명 이상이라면 그들이 인접하게 선택되었는지 찾아주고, 4명 미만이라면 인접 여부를 구할 필요가 없다. <- 백트래킹

 

인접 여부는 BFS를 활용하였는데, 원해 하던 방법을 거꾸로 이용하였다. 먼저 선택된 아이들의 visited를 true로 바꿔주고 탐색하면서 false로 바꿔주었다.


[JAVA 코드]

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.LinkedList;
import java.util.Queue;

public class Main {
	
	static BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
	
	static int result;
	static int [] selected = new int [7];
	static int [][] map = new int [5][5];
	static boolean [][] visited;
	static int [] dr = {-1, 0, 1, 0}, dc = {0, 1, 0, -1}; 
	
	static class Point {
		int r, c;
		
		public Point(int r, int c) {
			this.r = r;
			this.c = c;
		}
	}

	public static void main(String[] args) throws IOException {
		for(int r = 0; r < 5; r++) {
			String line = br.readLine();
			for(int c = 0; c < 5; c++) {
				if(line.charAt(c) == 'S') {
					map[r][c] = 1; // 이다솜파
				} else {
					map[r][c] = 0; // 임도연파
				}
			}
		}
		
		comb(0, 0);
		
		System.out.println(result);
	}

	private static void comb(int idx, int start) {
		if(idx == 7) {
			// 일단 뽑은 아이들 체크
			int s = 0, y = 0; // 이다솜파, 임도연파
			visited = new boolean [5][5];
			for(int i = 0; i < 7; i++) {
				int r = selected[i] / 5;
				int c = selected[i] % 5;
				
				if(map[r][c] == 1) s++;
				else			   y++;
				visited[r][c] = true;
			}
			
			// 이다솜파가 4명 이상인 경우에만 연결 체크
			if(s >= 4) {
				if(isConnected()) {
					result++;
				}
			}
			return;
		}
		
		for(int i = start; i < 25; i++) {
			selected[idx] = i;
			comb(idx + 1, i + 1);
		}
	}

	private static boolean isConnected() {
		Queue<Point> Q = new LinkedList<>();
		
		Q.add(new Point(selected[0] / 5, selected[0] % 5));
		visited[selected[0] / 5][selected[0] % 5] = false; // 선택 해제
		int cnt = 0; // 인접해있는 아이가 몇 명인지
		
		while(!Q.isEmpty()) {
			Point now = Q.poll();
			cnt++;
			
			for(int i = 0; i < 4; i++) {
				int nr = now.r + dr[i];
				int nc = now.c + dc[i];
				
                // 인덱스를 벗어나거나, 선택된 아이가 아닌경우
				if(nr < 0 || nr >= 5 || nc < 0 || nc >= 5|| !visited[nr][nc]) continue;
				
				Q.add(new Point(nr, nc));
				visited[nr][nc] = false; // 선택 해제
			}
		}
		
		if(cnt == 7) return true;
		else		 return false;
	}
}

'알고리즘 > BAEKJOON' 카테고리의 다른 글

[백준] 14890 경사로 (Java)  (0) 2022.04.26
[백준] 1593 문자 해독 (Java)  (0) 2022.04.22
[백준] 1600 말이 되고픈 원숭이 (Java)  (0) 2022.04.19
[백준] 2636 치즈 (Java)  (0) 2022.04.17
[백준] 14891 톱니바퀴 (Java)  (0) 2022.04.17

댓글