📌 고정 게시글

📢 공지합니다

이 게시글은 메인 페이지에 항상 고정되어 표시됩니다.

최코딩의 개발

[백준] 10819번 본문

코딩테스트/백준

[백준] 10819번

seung_ho_choi.s 2024. 2. 1. 23:06
728x90

사이트

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

 

10819번: 차이를 최대로

첫째 줄에 N (3 ≤ N ≤ 8)이 주어진다. 둘째 줄에는 배열 A에 들어있는 정수가 주어진다. 배열에 들어있는 정수는 -100보다 크거나 같고, 100보다 작거나 같다.

www.acmicpc.net

 

문제 

 

분석

문제는 뭔가 쉬워보여서 바로 도전했지만 그렇지가 않았다. 

초반에 큰수 작은수로 정렬해서 어떻게든 해볼려 했는데 뭔가 이상했다... 

그래서 문제 유형을 봤더니 백트래킹... 즉 재귀함수를 사용해야 했다. 

재귀함수가 너무 어렵다... 

 

필자가 생각한 알고리즘은 재귀함수를 구현해서 만약 입력이 6개면 트리구조 처럼 

1 2 3 4 5 6 /// 1 2 3 4 6 5 // 1 2 3 5 4 6 이렇게 끝의 있는 숫자를 바꾸면서 구현하고 싶었다. 

하지만 너무 어렵웠고 아직 미숙해서 다른사람들이 한거를 참고해서 만들었다...  

그래도 내가 생각한 알고리즘이 맞았기에 만족은 한다!! 

서론이 너무길었다. 본론 시작 !! 

 

static int n;
static int [] arr;

static int [] result;

static int max=Integer.MIN_VALUE;

static boolean[] visit;

다음과 같이 스태틱 필드 변수를 선언했다. 다른건 다 그렇다 쳐도 visit boolean 배열을 추가한 이유는 숫자를 바꿀때 기록하기 위함이다. 

public static void main(String[] args) throws IOException {
    BufferedReader br=new BufferedReader(new InputStreamReader(System.in));
    StringTokenizer st;
    n=Integer.parseInt(br.readLine());
    arr=new int[n];
    st=new StringTokenizer(br.readLine());
    for(int i=0; i<n; i++){
        arr[i]=Integer.parseInt(st.nextToken());
    }
    visit=new boolean[n];
    result=new int[n];
    dfs(0);
    System.out.println(max);
}

입력이 시작되고 dfs(0)을 호출함으로써 본격적인 코드가 실행된다! 

 

public static void dfs(int depth){
    if(n==depth){
        int sum=0;
        for(int i=0; i<n-1; i++){
            sum+=Math.abs(result[i]-result[i+1]);
        }
        max=Math.max(sum,max);
        return;
    }

    for (int i=0; i<n; i++){
        if(!visit[i]){
            visit[i]=true;
            result[depth]=arr[i];
            dfs(depth+1);
            visit[i]=false;
        }
    }

}

여기가 dfs 함수 구조이다 차근 차근 보자. 

일단 들어온 값이 0이므로 n의 크기는 6으로 가정했을때 크기가 맞지 않으므로 아래 for문으로 이동한다. 

즉 저 if문은 배열의 요소들이 다 정렬되었을 때 실행이 된다. 

 

for (int i=0; i<n; i++){
    if(!visit[i]){
        visit[i]=true;
        result[depth]=arr[i];
        dfs(depth+1);
        visit[i]=false;
    }
}

중요한 로직은 바로 이거다! 집중해서 읽자 

for문으로 들어오면 i=0일때 visit[0]은 일단 false 이므로 들어온다 .

 

dfs(0)

그러고나서 true로 변환시켜주고 arr[0] 즉 우리가 입력한 배열 요소의 값을 result[depth]에 저장한다. 즉 dfs(0) 했을때 저 0이다.

그러면 result 배열의 첫번째 요소는 저장이 된것이다. 그다음 dfs(1)을 호출한다 여기서 중요한점은 아직 dfs(0)은 끝나지 않았다는 것이다! 

 

dfs(1) 쭉

depth가 1이면 for문으로 들어온다. 이때 visit[0]은 true라서 visit[1]이 들어온다. 그럼 동일하게 result에 또 저장이 된다. 

이렇게 쭉 저장되다가 depth가 5가되면 result 배열은 완성이 되었고 dfs(6)을 호출한다. 

if(n==depth){
    int sum=0;
    for(int i=0; i<n-1; i++){
        sum+=Math.abs(result[i]-result[i+1]);
    }
    max=Math.max(sum,max);
    return;
}

그럼 위에 있는 if문에 걸리면서 Math.max를 통해 배열에 합한 값들이 max에 저장이 된다. 그리고 return 하게 된다. 

 

변화

그럼 dfs(6) 함수는 끝나게 되고 다시 dfs(5) 함수로 오게 된다.

for (int i=0; i<n; i++){
    if(!visit[i]){
        visit[i]=true;
        result[depth]=arr[i];
        dfs(depth+1);
        visit[i]=false;
    }
}

그럼 dfs(5) 함수는 위에 있는 visit[i]=false를 실행하게 된다. 이떄 dfs(5) 함수일때 i는 5이므로 visit[5]는 true가 아닌 false가 된다.

 

그 다음 어떻게 될까??? for 문이 끝났으므로 dfs(5) 도 끝났다! 그럼 dfs(4)가 호출이된다. 

위와 동일하게 dfs(4)도 visit[4]가 false로 바뀌고 다음 for문 i=5가 저장이 된다. 

이전: result[4]=arr[4]

바뀐후: result[4]=arr[5] 이렇게 말이다. 즉 필자가 앞에서 말했던것처럼 순서가 바뀐것이다! 

 

그럼 다시 dfs(5)로 호출이 되고 새롭게 호출되므로 for문을 처음 부터 돌려 

이전: result[5]=arr[5]

바뀐후: result[5]=arr[4] 이렇게 저장이 된다.

 

그러고 나서 또 dfs(6)을 호출하고 무한 반복이 되다가 depth가 0일떄 즉 dfs(0) 일때 for문이 완료됐으면 종료되는 것이다! 

종료되면서 최대값을 반환하는 것이다!! 

 

전체 코드

package bra;

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

public class Bra10819 {

    static int n;
    static int [] arr;

    static int [] result;

    static int max=Integer.MIN_VALUE;

    static boolean[] visit;
    public static void main(String[] args) throws IOException {
        BufferedReader br=new BufferedReader(new InputStreamReader(System.in));
        StringTokenizer st;
        n=Integer.parseInt(br.readLine());
        arr=new int[n];
        st=new StringTokenizer(br.readLine());
        for(int i=0; i<n; i++){
            arr[i]=Integer.parseInt(st.nextToken());
        }
        visit=new boolean[n];
        result=new int[n];
        dfs(0);
        System.out.println(max);
    }
    public static void dfs(int depth){
        if(n==depth){
            int sum=0;
            for(int i=0; i<n-1; i++){
                sum+=Math.abs(result[i]-result[i+1]);
            }
            max=Math.max(sum,max);
            return;
        }

        for (int i=0; i<n; i++){
            if(!visit[i]){
                visit[i]=true;
                result[depth]=arr[i];
                dfs(depth+1);
                visit[i]=false;
            }
        }

    }
}

 

결과

 

느낀점

와 진짜 재귀함수 너무 어렵다... 이 정답률이 65프로인데 사람들은 어떻게 맞힌 걸까??? 

필자도 알고리즘은 알고 있으나 직접 코드로 못써... 참조했는데... 

열심히 노력하자 풀어보니깐 또 어렵진 않았다.. 

그래프가 최곤데 ㅜㅜ 

728x90

'코딩테스트 > 백준' 카테고리의 다른 글

[백준] 15989번  (1) 2024.02.12
[백준] 14888번  (1) 2024.02.10
[백준] 1049번  (1) 2024.01.22
[백준] 9095번  (0) 2023.11.17
[백준] 14502번  (0) 2023.11.13