알고리즘/백준 문제 풀이

[BOJ] 4991. 로봇 청소기

바켱서 2020. 8. 6. 16:42

https://www.acmicpc.net/problem/4991

접근 방법

어려웠었다..

처음에는 그냥 BFS만 사용을 해서 차근차근 가까운 순서대로 먼지를 먹어주면 되는 줄 알았다.

하지만 구현은 완벽했지만 틀리는 것을 보고 아래의 힌트를 보았더니

' 순열 ' 이 포함 되어 있는 것을 보고

이 문제의 핵심은 청소기가 먼지를 먹는 순서에 따라 결과 값이 달라진다는 것을 알았다.


푸는 방식은 이렇게 했다.

  1. 입력 값을 받을 때 모든 먼지들의 값을 배열에 따로 저장을 한다.

  2. 각각의 먼지들의 거리를 BFS로 구한다.

     /**
      * 각각의 먼지를 구한 값
      * dust_dist[0][1] -> 이 뜻은 먼지들의 배열에서 0 에서 1로 갈 때의 distance의 값이다.
     **/
     static void getDustDist(){
             for(int i=0; i<total_dust.size()-1; i++){
                 for(int k=i+1; k<total_dust.size(); k++){
                     temp_dust_dist = Integer.MAX_VALUE;
                     visit = new int[h][w];
                     queue = new LinkedList<>();
                     visit[total_dust.get(i).x][total_dust.get(i).y] = 1;
                     queue.add(total_dust.get(i));
    
                                     // getPartialDist == BFS(endLocation)
                     getPartialDist(total_dust.get(k)); 
                     dust_dist[i][k] = temp_dust_dist;
                     dust_dist[k][i] = temp_dust_dist;
                 }
             }
         }
  3. 청소기에서 각각의 먼지들의 거리 또한 존재해야 하기 때문에 구하고 배열에 넣는다.

     static void getCleanerDustDist(){
             for(int i=0; i<total_dust.size(); i++){
                 temp_dust_dist = Integer.MAX_VALUE;
                 visit = new int[h][w];
                 queue = new LinkedList<>();
                 visit[cleaner.x][cleaner.y] = 1;
                 queue.add(cleaner);
    
                 getPartialDist(total_dust.get(i));
                 cleaner_dust_dist[i] = temp_dust_dist;
             }
         }
  4. 이제 어느 먼지를 먼저 먹을 지에 대한 순열을 구하고 ans에 최소값을 대입해주면 된다.

     static void permutation(int[] arr, int depth, int r) {
             if (depth == r) {
    
                 ans = Math.min(ans,getTotalDist(arr));
                 return;
             }
    
             for (int i=depth; i<total_dust.size(); i++) {
                 swap(arr, depth, i);
                 permutation(arr, depth + 1, r);
                 swap(arr, depth, i);
             }
         }
         static int getTotalDist(int[] arr) {
             int tempTotalDist = 0;
             tempTotalDist = cleaner_dust_dist[arr[0]];
             if(tempTotalDist == Integer.MAX_VALUE) return Integer.MAX_VALUE;
             for(int i=0; i<arr.length-1; i++){
                 int dist = dust_dist[arr[i]][arr[i+1]];
                 if(dist == Integer.MAX_VALUE) return Integer.MAX_VALUE;
    
                 tempTotalDist += dist;
             }
             return tempTotalDist;
         }

Need Know

  1. BFS
  2. 순열

전체 코드 ( Java )

import java.io.*;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.Queue;
import java.util.StringTokenizer;

class Main {
    static BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
    static BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(System.out));
    static int w;
    static int h;
    static char[][] map;
    static int[][] dust_dist;
    static int[] cleaner_dust_dist;
    static Queue<Location> queue;
    static int temp_dust_dist;
    static int[][] visit;
    static ArrayList<Location> total_dust;
    static Location cleaner;
    static int[] dx = {-1,1,0,0};
    static int[] dy = {0,0,-1,1};
    static int ans ;
    public static void main(String[] args) throws IOException {
        set();

        bw.flush();
        bw.close();
        br.close();
    }
    static void set() throws IOException {
        while(true) {
            StringTokenizer st = new StringTokenizer(br.readLine());
            w = Integer.parseInt(st.nextToken());
            h = Integer.parseInt(st.nextToken());
            if(w==0 && h==0) break;

            map = new char[h][w];
            ans = Integer.MAX_VALUE;
            total_dust = new ArrayList<>();
            for(int i=0; i<h; i++){
                String str = br.readLine();
                for(int k=0; k<w; k++){
                    map[i][k] = str.charAt(k);
                    if(map[i][k]=='o') cleaner = new Location(i,k);
                    if(map[i][k]=='*') total_dust.add(new Location(i,k));
                }
            }
            cleaner_dust_dist = new int[total_dust.size()];
            dust_dist = new int[total_dust.size()][total_dust.size()];

            getCleanerDustDist();

            getDustDist();

            int[] index_arr = new int[total_dust.size()];
            for(int i = 0; i<total_dust.size(); i++){
                index_arr[i] = i;
            }
            permutation(index_arr, 0, total_dust.size());
            if(ans == Integer.MAX_VALUE) bw.write(-1 + "\n");
            else{
                bw.write(ans +"\n");
            }
        }
    }

    static void permutation(int[] arr, int depth, int r) {
        if (depth == r) {

            ans = Math.min(ans,getTotalDist(arr));
            return;
        }

        for (int i=depth; i<total_dust.size(); i++) {
            swap(arr, depth, i);
            permutation(arr, depth + 1, r);
            swap(arr, depth, i);
        }
    }
    static int getTotalDist(int[] arr) {
        int tempTotalDist = 0;
        tempTotalDist = cleaner_dust_dist[arr[0]];
        if(tempTotalDist == Integer.MAX_VALUE) return Integer.MAX_VALUE;
        for(int i=0; i<arr.length-1; i++){
            int dist = dust_dist[arr[i]][arr[i+1]];
            if(dist == Integer.MAX_VALUE) return Integer.MAX_VALUE;

            tempTotalDist += dist;
        }
        return tempTotalDist;
    }
    static void swap(int[] arr, int depth, int i) {
        int temp = arr[depth];
        arr[depth] = arr[i];
        arr[i] = temp;
    }
    static void getCleanerDustDist(){
        for(int i=0; i<total_dust.size(); i++){
            temp_dust_dist = Integer.MAX_VALUE;
            visit = new int[h][w];
            queue = new LinkedList<>();
            visit[cleaner.x][cleaner.y] = 1;
            queue.add(cleaner);

            getPartialDist(total_dust.get(i));
            cleaner_dust_dist[i] = temp_dust_dist;
        }
    }
    static void getDustDist(){
        for(int i=0; i<total_dust.size()-1; i++){
            for(int k=i+1; k<total_dust.size(); k++){
                temp_dust_dist = Integer.MAX_VALUE;
                visit = new int[h][w];
                queue = new LinkedList<>();
                visit[total_dust.get(i).x][total_dust.get(i).y] = 1;
                queue.add(total_dust.get(i));

                getPartialDist(total_dust.get(k));
                dust_dist[i][k] = temp_dust_dist;
                dust_dist[k][i] = temp_dust_dist;
            }
        }
    }
    static void getPartialDist(Location end){
        loop : while(!queue.isEmpty()){
            Location nowLoc = queue.poll();

            for(int i=0; i<4; i++){
                int nx = nowLoc.x + dx[i], ny = nowLoc.y + dy[i];
                if(nx >= h || ny >= w || nx < 0 || ny < 0 || visit[nx][ny] != 0 || map[nx][ny] == 'x') continue;
                if( nx == end.x && ny == end.y ){
                    temp_dust_dist = visit[nowLoc.x][nowLoc.y];
                    break loop;
                }
                queue.add(new Location(nx,ny));
                visit[nx][ny] = visit[nowLoc.x][nowLoc.y] +1;
            }
        }
    }
}class Location{
    int x;
    int y;

    public Location(int x, int y) {
        this.x = x;
        this.y = y;
    }
}