코딩테스트/SWEA

[SWEA] 3234 준환이의 양팔저울

5월._. 2022. 2. 20.
728x90

1. 문제

 

SW Expert Academy

SW 프로그래밍 역량 강화에 도움이 되는 다양한 학습 컨텐츠를 확인하세요!

swexpertacademy.com

무게 추를 올릴 때 오른쪽 위에 올라가 있는 무게의 총합이 왼쪽에 올라가 있는 무게의 총합보다 더 커져서는 안 된다.

준환이가 양팔 저울에 모든 무게추를 올리는 방법은 총 몇 가지가 있을까?


2. 풀이

왼쪽 저울에 올라갈 순열을 찾는다.

cnt==N이면 다 찾은 경우이므로 result에 1을 더한다.

경우의 수를 찾다가 중간에 이미 left가 나머지+right보다 더 크면 그 뒤의 경우의 수((N-cnt)! * 2^(N-cnt))를 전부 더해주고 끝낸다.

0부터 N-1 중에 이미 뽑은 추는 제외하고 나머지를 오른쪽, 왼쪽으로 저울에 올린다. (재귀호출)

오른쪽으로 올릴 때는 left보다 right+현재 추 무게가 같거나 작을 때만 가능하다.

import java.io.*;
import java.util.*;

public class D4_3234_준환이의양팔저울 {
   private static int N, result;
   private static int[] weights;

   public static void main(String[] args) throws IOException {
      BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
      StringTokenizer st;
      StringBuilder sb = new StringBuilder();

      int T = Integer.parseInt(in.readLine());

      for (int tc = 1; tc <= T; tc++) {
         sb.append("#").append(tc).append(" ");
         result = 0;
         int total = 0;

         N = Integer.parseInt(in.readLine());
         weights = new int[N];

         st = new StringTokenizer(in.readLine());
         for (int i = 0; i < N; i++) {
            weights[i] = Integer.parseInt(st.nextToken());
            total += weights[i];
         }

         measure(0, 0, 0, total, 0);

         sb.append(result).append("\n");
      }

      System.out.print(sb);
   }

   private static void measure(int cnt, int left, int right, int stock, int flag) {
      int[] pow = {1, 2, 4, 8, 16, 32, 64, 128, 256, 512};
      int[] factorial = {1, 1, 2, 6, 24, 120, 720, 5040, 40320, 362880};
 
      if (cnt == N) {
         ++result;
         return;
      }

      if (left >= stock + right) {
         result += factorial[N - cnt] * pow[N - cnt];
         return;
      }

      for (int i = 0; i < N; i++) {
         if ((flag & 1 << i) != 0) continue;
         measure(cnt + 1, left + weights[i], right, stock - weights[i], flag | 1 << i);
         if (left >= right + weights[i]) {
            measure(cnt + 1, left, right + weights[i], stock - weights[i], flag | 1 << i);
         }
      }
   }
}

3. 결과

시간초과가 너무너무 많이 났던 문제였다. 

그래서 2의 n제곱을 미리 만들어 놓기도 하고, 팩토리얼도 9!까지 만들어놨다. 그런데도 시간초과가 났다.

가지치기도 잘 한 것 같은데 계속 틀려서 찾아보니 total이 문제였다. total을 static변수로 설정하고 (left >= total-left) 비교했었는데 함수 내에 있는 매개변수 접근보다 전역변수 접근이 더 느려서 그랬나보다. 원거리 변수보다 근거리 변수 접근이 더 빠른 것이 당연하기는 하다.

 

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

[SWEA] 1238 Contact - JAVA  (0) 2022.02.22
[SWEA] 1247 최적경로 - JAVA  (0) 2022.02.20
[SWEA] 4012 요리사 - JAVA  (0) 2022.02.16
[SWEA] 5644 무선충전 - JAVA  (0) 2022.02.16
[SWEA] 6808 규영이와 인영이의 카드게임 - JAVA  (0) 2022.02.14

댓글