728x90
반응형
SMALL
https://softeer.ai/practice/7726
핵심 설명
1. bfs를 사용해서 (사람 혹은 유령) 과 (출구) 의 최단거리를 구해서 비교하면 된다.
2. 사람이 먼저 도착하면 Yes 출력 아니면 No 출력
이슈 4가지
1. 유령은 벽을 통과할 수 있게 분기처리 해주자. (기본조건)
이걸 안해주니 2번째 테케가 아마 틀렸었던거같습니다
4 6
...#.D
...#..
.GN#..
G.....
if(map[nx][ny] == '#' && !ghostFlag){ // 사람은 벽 이동불가, 유령은 통과가능 (이슈1)
continue;
}
그래도 다음과 같이 시간초과가 발생했습니다.
2. bfs로 완탐하기전에 목적지 위치와의 최단거리를 찾자마자 while문을 종료 시켜주자. (시간초과 미세하게 해결)
시간초과를 해결하고자 추가했던 내용인데 속시원하게 해결되진 않았습니다.
if(dis[dest.x][dest.y] != 0){ // 목적지 발견시 바로 종료 (이슈2)
return dis[dest.x][dest.y];
}
3. 유령은 출구에서 가장 가까운 한명만 찾아주자. (피타고라스의 정리 a2 + b2 = c2 이용) (시간초과 완전 해결)
2번만으로는 시간초과가 줄지 않아서, 원인을 찾다가 3번을 적용하니 런타임에러 제외하고 전부 테케 통과했습니다.
int selectGhost = 0;
int disGhostAndExit = Integer.MAX_VALUE;
for(int i=0; i<ghost.size(); i++){
int a = Math.abs(dest.x-ghost.get(i).x);
int b = Math.abs(dest.y-ghost.get(i).y);
if( disGhostAndExit > (a*a)+(b*b) ){
disGhostAndExit = (a*a)+(b*b);
selectGhost = i;
}
}
4. 유령이 없는 경우를 예외처리 해주자. (소프티어 '연습문제 톡' 에 누가 이의제기 글 올려서 테케가 추가된것같네요) (히든 테케)
런타임에러 발생시 실행결과 상세보기 버튼 클릭해서 보면
마지막 5개의 테스트케이스가 런타임에러일테고
아마 본 이슈처럼 유령이 없는 경우의 케이스일거라고 보여지네요
// 이슈4 유령 없을때 예외처리 추가
if(!ghost.isEmpty())
ghostCnt = bfs(map, ghost.get(selectGhost), dest, true);
else
ghostCnt = Integer.MAX_VALUE;
핵심 코드
"이슈" 로 검색해보시면 쉽게 찾으실 수 있습니다.
전체 코드
import java.io.*;
import java.util.*;
public class Main {
public static int dx[] = {-1, 0, 1, 0};
public static int dy[] = {0, 1, 0, -1};
public static class Point{
int x;
int y;
public Point() {
}
Point(int x, int y){
this.x = x;
this.y = y;
}
}
public static void main(String[] args) throws IOException{
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(System.out));
int dap = 0;
StringTokenizer st = new StringTokenizer(br.readLine());
int n = Integer.parseInt(st.nextToken());
int m = Integer.parseInt(st.nextToken());
char map[][] = new char[n][m];
Point nam = new Point();
Point dest = new Point();
ArrayList<Point> ghost = new ArrayList<>();
for(int i=0; i<n; i++){
String line = br.readLine();
for(int j=0; j<m; j++){
char c = line.charAt(j);
// System.out.print(c);
map[i][j] = c;
if(c == 'N'){
nam.x = i; nam.y = j;
}
if(c == 'D'){
dest.x = i; dest.y = j;
}
if(c == 'G'){
ghost.add(new Point(i, j));
}
}
// System.out.println();
}
int namCnt = bfs(map, nam, dest, false);
// System.out.println("namCnt : " + namCnt);
int ghostCnt = Integer.MAX_VALUE;
// 유령 전체 다 bfs 돌리니 시간초과 발생 (이슈3)
// for(int i=0; i<ghost.size(); i++){
// int calCnt = bfs(map, ghost.get(i), dest, true);
// // System.out.println("calCnt[" + i + "] : " + calCnt);
// ghostCnt = Math.min(ghostCnt, calCnt);
// }
// x,y 좌표 계산해서 출구랑 가장 가까운 거리의 유령을 찾고 그녀석만 비교해주자
int selectGhost = 0;
int disGhostAndExit = Integer.MAX_VALUE;
for(int i=0; i<ghost.size(); i++){
int a = Math.abs(dest.x-ghost.get(i).x);
int b = Math.abs(dest.y-ghost.get(i).y);
if( disGhostAndExit > (a*a)+(b*b) ){
disGhostAndExit = (a*a)+(b*b);
selectGhost = i;
}
}
// 이슈4 유령 없을때 예외처리 추가
if(!ghost.isEmpty())
ghostCnt = bfs(map, ghost.get(selectGhost), dest, true);
else
ghostCnt = Integer.MAX_VALUE;
// System.out.println("ghostCnt[" + selectGhost + "] : " + ghostCnt);
// 출력
if(namCnt < ghostCnt && namCnt != 0){
bw.write("Yes");
}else{
bw.write("No");
}
bw.flush();
bw.close();
}
public static int bfs(char map[][], Point mop, Point dest, boolean ghostFlag){
boolean v[][] = new boolean[map.length][map[0].length];
int dis[][] = new int[map.length][map[0].length];
for(int i=0; i<map.length; i++) {
for (int j = 0; j < map[0].length; j++) {
v[i][j] = false;
dis[i][j] = 0;
}
}
// 시작위치 방문표시하고 큐에 추가
v[mop.x][mop.y] = true;
Queue<Point> q = new LinkedList<>();
q.add(mop);
// 큐에서 하나씩 꺼내면서 너비탐색 시작
while(!q.isEmpty()){
Point cur = q.poll();
// System.out.println();
// for(int i=0; i<map.length; i++){
// for(int j=0; j<map[0].length; j++){
// System.out.print(dis[i][j] + " ");
// }
// System.out.println();
// }
// 상하좌우로 이동해볼건데
for(int i=0; i<4; i++){
int nx = cur.x + dx[i];
int ny = cur.y + dy[i];
if(nx < 0 || ny < 0 || nx >= map.length || ny >= map[0].length){ // 맵에서 벗어나지 않고
continue;
}
// System.out.println("(" + nx + ", " + ny + ")" + " : " + dis[nx][ny]);
if(v[nx][ny] == true){ // 기방문은 이동불가
continue;
}
if(map[nx][ny] == '#' && !ghostFlag){ // 사람은 벽 이동불가, 유령은 통과가능 (이슈1)
continue;
}
v[nx][ny] = true;
dis[nx][ny] = dis[cur.x][cur.y]+1;
if(dis[dest.x][dest.y] != 0){ // 목적지 발견시 바로 종료 (이슈2)
return dis[dest.x][dest.y];
}
q.add(new Point(nx, ny));
}
}
return dis[dest.x][dest.y];
}
}
728x90
반응형
LIST
'알고리즘 단련장 > 소프티어' 카테고리의 다른 글
[소프티어] 플레이페어 암호 자바 풀이 시간초과 해결 완료 (HSAT 3회 정기 코딩 인증평가 기출) (0) | 2024.08.25 |
---|---|
[소프티어] 함께하는 효도 자바 풀이 dfs 쉽게 설명 쉬운 해설 (0) | 2024.08.25 |
[소프티어] 자동차 테스트 자바 풀이 이진탐색 직접구현 함수사용 모두 해보기 (HSAT 7회 정기 코딩 인증평가 기출) (0) | 2024.08.24 |
[소프티어] 순서대로 방문하기 자바 풀이 DFS 백트래킹 (HSAT 7회 정기 코딩 인증평가 기출) (0) | 2024.08.23 |
[소프티어] 우물 안 개구리 자바 풀이 레벨3 단순구현 (0) | 2024.07.21 |