[백준] 1802. 종이접기 _ Java

jii0_0·2023년 3월 9일
0

Beakjoon Online Judge

목록 보기
22/22

종이접기 (Silver I)

문제 링크

성능 요약

메모리: 13980 KB, 시간: 140 ms

분류

애드 혹(ad_hoc), 분할 정복(divide_and_conquer)

문제 설명

동호는 종이를 접는데 옆에서 보고 접으려고 한다. 옆에서 본다는 말은 아래 그림과 같이 본다는 뜻이다. 동호는 종이를 반으로 접을 때, 아래와 같이 두가지중 하나로만 접을 수 있다.

  1. 오른쪽 반을 반시계 방향으로 접어서 왼쪽 반의 위로 접는다.
  2. 오른쪽 반을 시계 방향으로 접어서 왼쪽 반의 아래로 접는다.

아래의 그림은 위의 설명을 그림으로 옮긴 것이다.

한 번의 종이 접기가 끝났을 때, 동호는 종이 접기를 원하는 만큼 더 할 수 있다. 종이 접기를 한번 접을 때 마다 두께는 2배가 되고 길이는 절반이 될 것이다.

종이 접기를 여러 번 했을 때 (안접을 수도 있다), 동호는 종이를 다시 피기로 했다. 그러고 나서 다시 접고 이렇게 놀고 있었다. 옆에서 보고 있던 원룡이는 동호를 위해 종이를 접어서 주기로 했다.(원룡이는 동호의 규칙대로 접지 않는다.) 동호는 그리고 나서 원룡이가 접었다 핀 종이를 다시 동호의 규칙대로 접을 수 있는지 궁금해졌다.

위의 저 종이를 접었다 피면 다음과 같은 그림처럼 펴진다.

종이가 시계방향으로 꺽여있으면 OUT이고, 반시계방향으로 꺾여있으면 IN이다.

종이가 접혀있는 정보가 왼쪽부터 오른쪽까지 차례대로 주어졌을 때, 이 종이를 동호의 규칙대로 접을 수 있는지 없는지를 구하는 프로그램을 작성하시오.

입력

첫째 줄에 테스트 케이스의 개수 T가 주어진다. T는 1000보다 작거나 같은 자연수이다. 둘째 줄부터 T개의 줄에 각각의 종이가 어떻게 접혀있는지가 주어진다. 종이의 정보는 문자열로 주어지며, 1은 위의 그림에서 OUT을 의미하고 0은 위의 그림에서 IN을 의미한다. 예를 들어, 위의 그림과 같은 모양은 100으로 나타낼 수 있다. 문자열의 길이는 3000보다 작으며, 항상 2N-1꼴이다. (N ≥ 1)

출력

T개의 줄에 차례대로 각각의 종이를 동호의 방법대로 다시 접을 수 있으면 YES를, 접을 수 없으면 NO를 출력한다.

문제 풀이

  • 종이를 반접고 그걸 또 반접고 하는 방식으로 접어나갈 수 있다
  • 그래서 숫자를 보고 중간을 기준으로 양쪽이 대칭이어야 하며
  • 대칭인걸 확인하고 해당 종이를 또 반반 나눠서 양쪽을 접을 수 있는 숫자인지 확인해주어야한다
  • 해당 종이가 한칸이 될때까지 양쪽을 쪼개서 확인하는 전형적인 분할정복의 문제였다.

Solution

import java.util.Arrays;
import java.util.Scanner;

public class Main {
    static char[] paper;
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        StringBuilder sb = new StringBuilder();
        int T = sc.nextInt();
        for(int i=0; i<T; i++) {
            String p = sc.next();
            int n = p.length();
            paper = new char[n];
            paper = p.toCharArray();

            if(check(0, n-1)) {
                sb.append("YES\n");
            } else {
                sb.append("NO\n");
            }
        } // test case

        System.out.println(sb.toString().trim());
    }

    public static boolean check( int start, int end) {
        if (start == end) { // 끝까지 탐색하면 true
            return true;
        }

        int mid = (start+end)/2; // 중간 값
        for(int i=start; i<mid; i++) {
            if(paper[i] == paper[end-i]) return false;
        }
        return check(start, mid-1) && check(mid+1, end); // 양쪽 동시 탐색

    }
}
profile
느려도 꾸준히

0개의 댓글