알고리즘/백준

1956_운동 (60%대에서 자꾸 틀림)

베리영young 2024. 3. 24. 18:11

사용 알고리즘: 플로이드 워셜

사용 언어: java

 

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.StringTokenizer;

//dfs를 왜 돌리세요? 플로이드를 마치고 나면 `map[i][i]`에 들어가는게 i에서 출발해서 i로 끝나는 사이클의 최소 길이인데요.
//  ㄴ 헐 그렇네

public class Main_bj_1956_운동 {
    static int v,e;
//    static ArrayList<Edge>[] map;
    static int[][] map;
    static int answer = 400000;
    public static void main(String[] args) throws IOException {
        input();
        floydwasher();

//        for (int start = 1; start < v+1; start++) {
//            boolean[] visited = new boolean[v+1];
////            visited[start] = true;
//            for (int secondstart = 1; secondstart < v+1; secondstart++) { //dfs
//                if (map[start][secondstart] != 10001) {
//                    visited[secondstart] = true;
//                    makeLittleCircle(secondstart, start, map[start][secondstart], visited);
//                    Arrays.fill(visited, false);
//                }
//            }
//        }
        for (int i = 1; i < v+1; i++) {
            for (int j = 1; j < v+1; j++) {
                if(i == j) continue;
                else {
                    if (map[i][j] != 10001 && map[j][i] != 10001) //가는 길, 오늘 길 둘 다 있어야 함
                        answer = Math.min(answer, map[i][j] + map[j][i]); //갔으면 돌아오는 거까지 체크해야지~
                }
            }
        }

        //운동 경로를 찾는 것이 불가능한 경우에는 -1을 출력 -> 이거 빼먹음...
        if(answer == 400000) System.out.println(-1);
        else System.out.println(answer);
    }

    private static void makeLittleCircle(int secondstart, int end, int sum, boolean[] visited) {
        if (secondstart == end) {
            answer = Math.min(sum, answer);
//            System.out.println(answer);
        }

        for (int thirdstart = 1; thirdstart < v+1; thirdstart++) {
            if(!visited[thirdstart] && map[secondstart][thirdstart] != 10001) {
                visited[thirdstart] = true;
                makeLittleCircle(thirdstart, end, sum+map[secondstart][thirdstart], visited);
                visited[thirdstart] = false;
            }
        }

    }

    private static void floydwasher() { //연결에 연결 + 갈 수 있는 최소값 갱신
        for (int i = 1; i < v+1; i++) {
            for (int j = 1; j < v+1; j++) {
                for (int k = 1; k < v+1; k++) {
                    if(i!=j && map[i][k] + map[k][j] < map[i][j]) { //아!!! 최대+최대 = 오버플로우로 마이너스 됨
                        map[i][j] = map[i][k] + map[k][j];
                    }
                }
            }
        }

//        for (int i = 0; i < v+1; i++) {
//            System.out.println(Arrays.toString(map[i]));
//        }
    }

    private static void input() throws IOException {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        StringTokenizer st = new StringTokenizer(br.readLine());
        v = Integer.parseInt(st.nextToken());
        e = Integer.parseInt(st.nextToken());

        map = new int[v+1][v+1];
//        Arrays.fill(map, Integer.MAX_VALUE); --> 2차원 배열은 이런 식으로 못 채운다
        for (int i = 0; i <= v; i++) {
            for (int j = 0; j <= v; j++) {
                map[i][j] = 10001;
            }
        }

        for (int i = 0; i < e; i++) {
            st = new StringTokenizer(br.readLine());
            int start = Integer.parseInt(st.nextToken());
            int end = Integer.parseInt(st.nextToken());
            int weight = Integer.parseInt(st.nextToken());

            map[start][end] = weight;
        }
    }

//    static class Edge {
//        int to;
//        int value;
//
//        public Edge(int to, int value) {
//            this.to = to;
//            this.value = value;
//        }
//    }
}

 

 

첫번째 틀림 -> Integer.MAX_VALUE 에 (+알파)가 되면 오버플로 때문에 -가 됨. 

                    -> 문제에서 최대 가중치는 10,000이라고 해서 Integer.MAX_VALUE가 아닌 적당한 값으로 바꿈

 

두번째 시간초과 -> dfs를 굳이 돌릴 필요가 없는데 돌림 (makeLittleCircle)

 

세번째 틀림 -> 가는 길이 있을 때, 무조건 더해버림(돌아오는 길이 없어서 max치를 찍어도) 

                    -> 가는 길이 있을 때 돌아오는 길도 있나 확인 후 더함

네번째 틀림 -> 문제에 조건으로 주어진 "길이 없으면 -1을 출력"을 빼먹음

 

===> 뭘 고쳐도 답이 안 나옴... 다른 블로그를 참고해봐도 로직이 같은데...

===> 플로이드 워셜에서 k를 for문 제일 밖에 둔 코드가 있어서 그렇게 바꿔봐도 똑같이 60%대에서 답이 안 나옴