재귀 함수 응용 문제

재귀함수를 활용한 실전 응용 문제


1. dessert

  • 문제

    • 농부 존은 소들의 저녁식사 줄 세우는 새로운 방법을 개발 했다. N(1~15)마리의 소들을 순서대로 세 워놓은 후, 각 소들 사이에 +, - , . 셋 중 1가지가 써져있는 냅킨을 배치해서 최종 결과가 0 이 되게 해야 하는 것이다. 점(.)이 써져있는 냅킨을 통해 더 큰 수를 만들 수 있게 된다. 아래와 같은 경우를 보자. (ps .이 써져있는 냅킨은 ‘공백’이라고 생각하면 된다.)

      1-2.3-4.5+6.7

      이와 같은 배치는 1-23-45+67 을 나타낸다. 결과는 0 이다. 10.11은 1011 로 해석된다.

  • 입력

    • 첫 째 줄에는 소들의 수 N이 입력된다.
  • 출력

    • 처음 20줄에 대해 가능한 20가지 답을 출력하는데, 사전 순으로 앞선 것을 출력한다. 순서는 +가 가장 앞서고 -와 . 이 순서대로 뒤따른다. 답이 20개 미만이면 가능한 답을 각 숫자와 문자 사이에 공백을 두고 출력한다. 모두 출력한다. 마지막 줄에는 가능한 답의 총 가지수를 출력한다.
  • 예제 입력

    • 7
  • 예제 출력

    • 1 + 2 - 3 + 4 - 5 - 6 + 7
      1 + 2 - 3 - 4 + 5 + 6 - 7
      1 - 2 + 3 + 4 - 5 + 6 - 7
      1 - 2 - 3 - 4 - 5 + 6 + 7 
      1 - 2 . 3 + 4 + 5 + 6 + 7 
      1 - 2 . 3 - 4 . 5 + 6 . 7
      6
      
  • 내 풀이

    • import java.io.*;
      import java.util.*;
          
      public class Main{
        int n;
        int[] symbol;
        char[] ch = {'+', '-', '.'};
        int count;
            
        public static void main(String[] arhs) throws IOException{
          BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
          Main m = new Main();
          m.n = Integer.parseInt(br.readLine());
          m.symbol = new int[m.n - 1];
              
          m.recur(0);
                
          // 전부 출력 끝난 후 마지막으로 누적된 count 출력
          System.out.println(m.count);
        }
            
        void recur(int current){
          // 기저조건 : 연산기호 개수가 (숫자개수 - 1)과 같다면 출력 후 연산기호 추가 중지
          if(current == n - 1){
            // evaluate() : 연산 수행 결과를 반환
            int result = evaluate();
                
            // 연산 수행 결과가 0이면 count++ 후 출력
            if(result == 0){
              count++;
                    
              // 카운트가 20을 초과하면 카운트만 올리고 출력은 안하기.
              if(count <= 20){
                print();
              }
            }
            return;
          }
              
          // 연산기호의 모든 경우의 수를 재귀호출로 완전탐색 수행
          // 중복 순열
          for(int i = 0; i < 3; i++){
            symbol[current] = i;
            recur(current + 1);
          }
        }
            
        // 연산 수행 결과를 반환
        int evaluate(){
          int myNum = 1;
          int mySym = 0;
          int sum = 0;
              
          // 연산기호를 나타내는 int형 배열을 통해 계산 수행
          for(int i = 0; i < symbol.length; i++){
                  
            // . 이 아니면 연산 수행
            if(symbol[i] == 0 || symbol[i] == 1){
              if(mySym == 0) sum += myNum;
              else sum -= myNum;
                  
              myNum = i + 2;
              mySym = symbol[i];
                    
              // . 이라면 뒤의 숫자를 현재 숫자와 이어붙이기 수행
            }else{
              if(i + 2 >= 10) myNum *= 100;
              else myNum *= 10;
                  
              myNum += i + 2;
            }
          }
              
          // 마지막 연산 수행 안된 것 마저 수행
          if(mySym == 0) sum += myNum;
          else sum -= myNum;
              
          // 연산 결과값 반환
          return sum;
        }
            
        // 조건에 맞는 식일 경우 실시간으로 출력
        void print(){
          for(int i = 0; i < symbol.length; i++){
            System.out.print(i + 1 + " ");
            System.out.print(ch[symbol[i]] + " ");
          }
          System.out.println(n);
        }
      }
      

2. inequal

  • 문제

    • 두 종류의 부등호 기호 ‘<’와 ‘>’가 k 개 나열된 순서열 A가 있다. 우리는 이 부등호 기호 앞뒤에 서로 다른 한 자릿수 숫자를 넣어서 모든 부등호 관계를 만족시키려고 한다. 예를 들어, 제시된 부등호 순서열 A가 다음과 같다고 하자.

      A ⇒ < < < > < < > < >

      부등호 기호 앞뒤에 넣을 수 있는 숫자는 0부터 9까지의 정수이며 선택된 숫자는 모두 달라야 한다. 아래는 부등호 순서열 A를 만족시키는 한 예이다.

      3 < 4 < 5 < 6 > 1 < 2 < 8 > 7 < 9 > 0

      이 상황에서 부등호 기호를 제거한 뒤, 숫자를 모두 붙이면 하나의 수를 만들 수 있는데 이 수를 주어진 부등호 관계를 만족시키는 정수라고 한다. 그런데 주어진 부등호 관계를 만족하는 정수는 하나 이상 존재한다. 예를 들어 3456128790 뿐만 아니라 5689023174도 아래와 같이 부등호 관계 A를 만족시킨다.

      5 < 6 < 8 < 9 > 0 < 2 < 3 > 1 < 7 > 4

      여러분은 제시된 k 개의 부등호 순서를 만족하는 (k+1) 자리의 정수 중에서 최대값과 최소값을 찾아야 한다. 앞서 설명한 대로 각 부등호의 앞뒤에 들어가는 숫자는 { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 } 중에서 선택해야 하며 선택된 숫자는 모두 달라야 한다. 프로그램의 실행시간은 0.5초를 넘을 수 없다.

  • 입력

    • 첫 줄에 부등호 문자의 개수를 나타내는 정수 가 주어진다. 그 다음 줄에는 k 개의 부등호 기호가 하나의 공백을 두고 한 줄에 모두 제시된다. k 의 범위는 2 <= k <= 9이다.
  • 출력

    • 여러분은 제시된 부등호 관계를 만족하는 자리의 최대, 최소 정수를 첫째 줄과 둘째 줄에 각각 출력해야 한다. 단 아래 예(1)과 같이 첫 자리가 0인 경우도 정수에 포함되어야 한다. 모든 입력에 답은 항상 존재하며 출력 정수는 하나의 문자열이 되도록 해야 한다.
  • 예제 입력 (1)

    • 2

      < >

  • 예제 출력 (1)

    • 897

      021


  • 예제 입력 (2)

    • 9

      > < < < > > > < <

  • 예제 출력 (2)

    • 9567843012

      1023765489

  • 내 풀이

    • import java.io.*;
      import java.util.*;
          
      public class Main{
        int n;
        int[] sign;
        int[] result;
        boolean[] resCheck;
        boolean boo;
            
        public static void main(String[] args) throws IOException{
          BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
          Main m = new Main();
          m.n = Integer.parseInt(br.readLine());
          m.sign = new int[m.n];
          m.result = new int[m.n + 1];
          m.resCheck = new boolean[10];
              
          StringTokenizer st = new StringTokenizer(br.readLine());
              
          // 다루기 쉽게 < 는 0, > 는 1 로 치환한다.
          for(int i = 0; i < m.sign.length; i++){
            if(st.nextToken().equals("<")){
              m.sign[i] = 0;
            }else{
              m.sign[i] = 1;
            }
          }
              
          // 조건에 해당되는 수들 중 최대값 출력
          m.recur2(0);
                
          // 일반 순열의 조건을 갖추기 위한 boolean 배열을 다시 초기화
          // 한 번 더 써야하기 때문에.
          Arrays.fill(m.resCheck, false);
                
          // 조건에 해당되는 수들 중 최소값 출력
          m.recur1(0);
        }
            
        // 조건에 해당되는 수들 중 최대값 출력
        void recur1(int current){
          // 조건에 해당되어 한 번 출력 후 재귀를 아예 빠져나오기.
          if(!boo) return;
              
          // 기저조건 : 숫자의 인덱스가 (입력된 부등호의 개수 + 1) 보다 같으면 기저조건에 해당 됨.
          if(current >= n + 1){
            // 나열되어있는 숫자를 차례대로 출력
            for(int i = 0; i < result.length; i++){
              System.out.print(result[i]);
            }
            System.out.println();
                  
            // 재귀함수 완전히 빠져나오기
            boo = false;
            return;
          }
              
          // 1 ~ 9 까지의 숫자를 재귀호출을 통해 완전탐색
          // 일반 순열
          for(int i = 0; i < 10; i++){
            // 일반 순열이기에 이미 들어가있는 숫자는 건너뛰기
            if(!resCheck[i]){
              // 인덱스 0 차례가 아닐 때
              if(current != 0){
                // 부등호에 따른 숫자의 조건이 맞지 않는 것들 거르기
                if(sign[current - 1] == 1 && result[current - 1] <= i){
                  continue;
                }else if(sign[current - 1] == 0 && result[current - 1] >= i){
                  continue;
                }
              }
                    
              // 이미 들어간 숫자를 거르기 위해 true 로 체크
              resCheck[i] = true;
              // 숫자 집어넣기
              result[current] = i;
              // 다음 인덱스에 숫자를 넣기 위해 재귀호출 수행
              recur1(current + 1);
              // 다음 인덱스의 재귀함수가 끝났기에 들어갔던 숫자를 다시 빼준다는 의미의 체크
              resCheck[i] = false;
            }
          }
        }
            
        // 조건에 해당되는 수들 중 최소값 출력
        // 위의 메서드와 for문(숫자)이 거꾸로 진행한다는 것, 재귀함수를 완전 빠져나오는 boolean값이 반대라는 것 외에 모두 동일
        void recur2(int current){
          if(boo) return;
              
          if(current >= n + 1){
            for(int i = 0; i < result.length; i++){
              System.out.print(result[i]);
            }
            System.out.println();
            boo = true;
            return;
          }
              
          for(int i = 9; i >= 0; i--){
            if(!resCheck[i]){
              if(current != 0){
                if(sign[current - 1] == 1 && result[current - 1] <= i){
                  continue;
                }else if(sign[current -1] == 0 && result[current - 1] >= i){
                  continue;
                }
              }
                  
              resCheck[i] = true;
              result[current] = i;
              recur2(current + 1);
              resCheck[i] = false;
            }
          }
        }
      }
      




© 2021. All rights reserved.

----------Powered by Hydejack----------

Jun's Development Blog