Two Dots
문제 복기
문제



위의 문제 설명에서처럼 주어진 조건은 다음과 같다.
모든 k개 점은 서로 다르다.
k는 4보다 크거나 같다. =>이동한 칸의 갯수를 세서 4이상이면 된다.
모든 점의 색은 같다. =>어떤 시작점에서 컬러를 기억해서 다음 재귀함수를 호출할 때 인자로 전달하여 컬러 갯수가 같도록 해야한다!
모든 1<i<=k-1에 대해 di와 di+1은 인접하다. 또, dk와 d1도 인접해야 한다. 두 점이 인접하다는 것은 각각의 점이 들어있는 칸이 변을 공유한다는 의미이다. "인접" : 상/하/좌/우 방향으로 붙어있다!
알고리즘 생각
문제에서 주어진 조건들을 하나씩 구현해보고, 발전시켜나간다.
k는 4보다 크거나 같다. =>이동한 칸의 갯수를 세서 4이상이면 된다.
모든 점의 색은 같다. =>어떤 시작점에서 컬러를 기억해서 다음 재귀함수를 호출할 때 인자로 전달하여 컬러 갯수가 같도록 해야한다!
di와 di+1은 인접하다. 또, dk와 d1도 인접해야 한다. =>"인접" : 상/하/좌/우 방향으로 붙어있다!
내가 작성한 코드 :
public static boolean dfs(int x,int y) {
//기준점(x,y)에서 이동한 갯수가 4인지 확인! 한칸씩 이동할 때마다 1씩 증가!
//4칸을 이동하기만 하면 true를 리턴.
if(dist[x][y]==4) return true;
c[x][y] = true;
dist[x][y] = 0;//기준점은 거리가 0!
for(int i=0;i<4;i++) {
int nx = x+dx[i],ny = y+dy[i];
if(nx<0 || nx>n-1 || ny<0 || ny>m-1) continue;
if(a[nx][ny] == a[x][y] && c[nx][ny]==false) {
dist[nx][ny] = dist[x][y]+1;
dfs(nx,ny);
}
}
return false;
}
정답 코드 : 싸이클을 찾기만 하면되기 대문에 거리 개념은 필요가 없다. - dist 배열 삭제. 재귀함수를 계속해서 호출해서 마지막에 리턴되는 값을 가져온다. 반환형이 boolean!
bool go(int x, int y, int cnt, char color) {
if (cnt == 4) return true;
for (int k=0; k<4; k++) {
int nx = x+dx[k], ny = y+dy[k];
if (0 <= nx && nx < n && 0 <= ny && ny < m) {
if (check[nx][ny] == false && a[nx][ny] == color) {
if (go(nx, ny, cnt+1, color)) {
return true;
}
}
}
}
return false;
}
하지만 위의 코드 역시 정답은 아니다. 싸이클이 존재하는지 판별하지 않기 때문이다. Solution#1. 현재 위치가 (x,y)일 때 방문했는지 확인하는 것에서 그치는 것이 아니라, 방문한 (x,y)이면 원래 좌표(x,y)에서부터 이동한 거리가 4이상인지 확인해준다.
bool go(int x, int y, int cnt, char color) {
if (cnt == 4) {
if(cnt-dist[x][y]>=4){//이동한 칸 갯수 - 기준점에서 (x,y)까지 거리 >=4
return true;
}
}
for (int k=0; k<4; k++) {
int nx = x+dx[k], ny = y+dy[k];
if (0 <= nx && nx < n && 0 <= ny && ny < m) {
if (check[nx][ny] == false && a[nx][ny] == color) {
if (go(nx, ny, cnt+1, color)) {
return true;
}
}
}
}
return false;
}
Solution#2 . 이전에 방문한 노드를 재방문한다 = 싸이클이 생겼다는 의미! =>하지만, BFS나 DFS는 기본적으로 노드를 한번씩만 방문하기 때문에, 다음에 방문할 노드(next;nx,ny)는 현재 노드를 기준(x,y)으로 그 이전 노드(past;px,py)가 아니여야 한다!
=>거리 개념은 불필요하다. 거리가 얼마나 떨어져있는지는 중요하지 않기 때문이다.
import java.util.*;
public class TwoDots_4th_pastxy_cycle {
public static boolean[][] c;
public static char[][] a;
public static int n;
public static int m;
public static int[] dx= {-1,1,0,0};
public static int[] dy= {0,0,-1,1};
public static boolean dfs(int x,int y,int px,int py,char color) {
if(c[x][y]) return true;//방문한 적이 있다면 true! 자세한 처리는 아래에서!
c[x][y] = true;
for(int i=0;i<4;i++) {
int nx = x+dx[i],ny = y+dy[i];
if(nx<0 || nx>n-1 || ny<0 || ny>m-1) continue;
if(!(nx==px && ny==py)) {
if(a[nx][ny]==color) {//이미 방문한 노드라도 방문해도 괜찮음. 싸이클 생성하는지 확인하는 것이 목표이니까!
if(dfs(nx,ny,x,y,color)) return true;
}
}
}
return false;
}
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
n = sc.nextInt();//행.
m = sc.nextInt();//열.
sc.nextLine();
a = new char[n][m];
c = new boolean[n][m];
for(int i=0;i<n;i++) {
String s = sc.nextLine();
for(int j=0;j<m;j++) {
a[i][j] = s.charAt(j);
}
}
for(int i=0;i<n;i++) {
for(int j=0;j<m;j++) {
if(c[i][j]) continue;
boolean ok = dfs(i,j,0,0,a[i][j]);
if(ok) {
System.out.println("Yes");
System.exit(0);
}
}
}
System.out.println("No");
}
}
Last updated
Was this helpful?