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

SW 14413. 격자판 칠하기 (BFS)

by son_i 2023. 5. 14.
728x90

SW Expert Academy

 

SW Expert Academy

SW 프로그래밍 역량 강화에 도움이 되는 다양한 학습 컨텐츠를 확인하세요!

swexpertacademy.com

자바

어려웠다. 그래도 가로 세로 비교해서 같은게 있으면 impossible로 구현을 했는데 런타임 오류가 자꾸나서 방법을 찾아보니까 BFS (너비우선탐색)  방법을 이용해야한다고 한다.

그래서 공부를 해보앗따.

import java.util.LinkedList;
import java.util.Queue;
import java.util.Scanner;


class Solution{
	static final int MAX_N = 10;
	static int[][] D = {{0,1},{-1,0},{1,0},{0,-1}};
	static int N;
	static int[][] Board = new int[MAX_N][MAX_N];
	static class Point {
		Point(int r,int c, int d) {
			row = r; col = c; dist=d;
		}
		int row,col,dist;
	}
	
	public static void main(String args[]) throws Exception{
		Scanner sc = new Scanner(System.in);
		N = sc.nextInt();
		for(int i=0;i<N;++i) 
			for(int j=0;j<N;++j) 
				Board[i][j] = sc.nextInt();

		int sRow,sCol,dRow,dCol;
		sRow = sc.nextInt(); sCol = sc.nextInt();
		dRow = sc.nextInt(); dCol = sc.nextInt();
		System.out.println(bfs(sRow,sCol,dRow,dCol));
	}

static int bfs(int sRow,int sCol,int dRow,int dCol) {
	boolean[][] visited = new boolean[MAX_N][MAX_N];
	Queue<Point> q = new LinkedList<>();
	visited[sRow][sCol] = true;
	q.add(new Point(sRow,sCol,0));
	
	while(!q.isEmpty()) {
		Point curr = q.remove();
		
		if(curr.row == dRow && curr.col ==dCol)
			return curr.dist;
	
	
	for(int i=0;i<4;++i) {
		int nr = curr.row + D[i][0], nc =  curr.col + D[i][1];
		if(nr < 0 || nr > N-1 || nc<0||nc>N-1) continue;
		if(visited[nr][nc] )continue;
		if(Board[nr][nc] ==1) continue;
		visited[nr][nc] = true;
		System.out.println("nr : "+nr+" "+"nc: "+nc+" "+curr.dist);
		q.add(new Point(nr,nc,curr.dist+1));
		}
	}
	return -1;
}
}

이건 너비우선 탐색을 이용한 최단거리 알고리즘이다. 복잡해보이지만 차근차근 보면 이해할 수 있다. 상하좌우 어느 곳을 먼저 가든지 더이상 길이 없는 것은 q에서 삭제되니까 더이상 고려가 되지 않는다.

 

BFS를 이용해서 문제를 풀어보자 ....

 

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


class Solution{
	static int D[][] = {{-1,0},{1,0},{0,-1},{0,1}};
	static int N;
	static int M;
	public static void main(String args[]) throws Exception{
		BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
		
		int T = Integer.parseInt(br.readLine());
		
		for(int i=1;i<=T;i++) {
			StringTokenizer st = new StringTokenizer(br.readLine());
			N = Integer.parseInt(st.nextToken());
			M = Integer.parseInt(st.nextToken());
			char arr[][] = new char[N][M];
			for(int j=0;j<N;j++) {
				String str = br.readLine();
				for(int k=0;k<M;k++) {
					char c = str.charAt(k);
					arr[j][k] = c;
					
					if(arr[j][k] =='?') {
						if(k>0) {
							if(arr[j][k-1]=='#') arr[j][k] = '.';
							else arr[j][k] = '#';
						}
						if(k ==0 && j>0) {
							if(arr[j-1][k] == '#') arr[j][k] = '.';
							else arr[j][k] = '#';
						}
					}
				}
			} 
			int ch = bfs(arr,N,M);
			if(ch == 1) System.out.println("#"+i+" "+"impossible");
			else System.out.println("#"+i+" "+"possible");
		}
	}
	public static int bfs(char arr[][],int N,int M) {
		boolean visited[][] = new boolean[N][M];
		Queue <Point> q= new LinkedList<>();
		visited[0][0] = true;
		q.add(new Point(0,0));
		int ch = 0;
		while(!q.isEmpty()) {
			Point curr = q.remove();
			
			for(int i=0;i<4;i++) {
				int nr = curr.row + D[i][0];
				int nc = curr.col + D[i][1];
				
				if(nr < 0 || nr > N-1 || nc < 0 || nc > M-1) continue;
				if(visited[nr][nc]) continue;
				if(arr[curr.row][curr.col] == arr[nr][nc]) {
					//기준노드랑 인접노드의 문자가 같으면 
					ch = 1;
					q.clear();
				}
				visited[nr][nc] = true;
				q.add(new Point(nr,nc));
			}
		}
		return ch;
	}
	static class Point {
		int row,col;
		Point(int r,int c){
			row = r; col = c;
		}
	}
}

35분만에 풀었는데 으음...... 73/68개 정답

무슨 반례가 있을까?

 

5/14 원인을 찾았따.

1
4 4
#???
????
?#??
???? 라는 입력이 있을 때

결과가

#.#. 
..#. 
.#.# 
#.#. 
#1 possible

이렇게 나왔다. 이미 ?인 구간을 거쳐서 값이 들어간 부분은 q에는 들어가지만 visited[nr][nc]가 true로 바뀌어서 더이상 점검하지 않는 것이다 ! 그래서

if(arr[nr][nc]=='?'){
	if(arr[curr.row][curr.col] == '#')	arr[nr][nc] = '.';
    else arr[nr][nc] = '#';
}

이 코드 부분을

if(arr[nr][nc] == '?') {
	if(arr[curr.row][curr.col]=='#') {
		arr[nr][nc] = '.';
		q.add(new Point(nr,nc));
		continue;
		}
	if(arr[curr.row][curr.col]=='.') {
		arr[nr][nc] = '#';
		q.add(new Point(nr,nc));
		continue;
	}
}

이렇게 바꿔주었다. visited여부를 true로 바꾸지는 않으면서 q에 넣어서 또 한 번 고려대상이 되게 함 !! 

 

full code

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


class Solution{
	static int D[][] = {{-1,0},{1,0},{0,-1},{0,1}};
	static int N;
	static int M;
	public static void main(String args[]) throws Exception{
		BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
		
		int T = Integer.parseInt(br.readLine());
		
		for(int i=1;i<=T;i++) {
			StringTokenizer st = new StringTokenizer(br.readLine());
			N = Integer.parseInt(st.nextToken());
			M = Integer.parseInt(st.nextToken());
			char arr[][] = new char[N][M];
			for(int j=0;j<N;j++) {
				String str = br.readLine();
				for(int k=0;k<M;k++) {
					char c = str.charAt(k);
					arr[j][k] = c;
					
				}
			} 
			
			int ch = bfs(arr,N,M);
			
			if(ch == 1) System.out.println("#"+i+" "+"impossible");
			else System.out.println("#"+i+" "+"possible");
		}
	}
	public static int bfs(char arr[][],int N,int M) {
		boolean visited[][] = new boolean[N][M];
		Queue <Point> q= new LinkedList<>();

		for(int i=0;i<N;i++) {
			for(int j=0;j<M;j++) {
				if(arr[i][j] != '?') {
					q.add(new Point(i,j));
				}
			}
		}
		int ch = 0;
		while(!q.isEmpty()) {
			Point curr = q.remove();
				for(int i=0;i<4;i++) {
					int nr = curr.row + D[i][0];
					int nc = curr.col + D[i][1];
					
					if(nr < 0 || nr > N-1 || nc < 0 || nc > M-1) continue;
					if(visited[nr][nc]) continue;
					if(arr[nr][nc] == '?') {
						if(arr[curr.row][curr.col]=='#') {
							arr[nr][nc] = '.';
							q.add(new Point(nr,nc));
							continue;
						}
						if(arr[curr.row][curr.col]=='.') {
							arr[nr][nc] = '#';
							q.add(new Point(nr,nc));
							continue;
						}
					}
					if(arr[nr][nc] !='?'){
						if(arr[curr.row][curr.col]=='#') {
							if(arr[nr][nc] == '#') {
								ch = 1;
								break;
							}
						}
						if(arr[curr.row][curr.col]=='.'){
							if(arr[nr][nc] == '.') {
								ch = 1;
								break;
							}
						}
					}
					visited[nr][nc] = true;
					q.add(new Point(nr,nc));
				}
			}
		return ch;
	}
	static class Point {
		int row,col;
		Point(int r,int c){
			row = r; col = c;
		}
	}
}

 

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

(자바) SWEA 15868. XOR 2차원 배열  (0) 2023.05.20
정렬 알고리즘  (0) 2023.05.18
SW 1288. 새로운 불면증 치료법  (0) 2023.05.05
SW 1928. Base64 Decoder  (0) 2023.05.05
SW 1940. 가랏! RC카 !  (0) 2023.05.05