문제의 크기가 클 경우에는 문제를 절반으로 나누어서 문제를 푼 후 두 개를 합치는 방식을 이용한다.

 

배열의 크기가 N인 집합이 있을 때 부분집합의 합이 M이 나오는 갯수를 찾는 문제이다.

이 문제의 경우는 N<=40이고 모든 부분 집합을 만들면 2^40가지가 나오므로 모든 경우의 수를 파악할 수 없다.

 

따라서 문제의 크기를 절반으로 나누어서 한쪽 절반과 다른쪽 절반에서 각각 푼 다음에 문제를 합쳐서 풀도록 한다.

먼저 절반에서 구한 모든 값들을 list에 넣고 left list의 값과 right list의 값의 합이 s인 가짓수를 찾는다.

 

부분집합의 크기는 양수이므로 둘 다 0인 경우는 마지막에 빼준다.

 

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

public class Main {
	public static long ans = 0;
	public static int arr[];
	public static int n, s;
	public static ArrayList<Integer> left, right;

	public static void main(String[] args) {
		Scanner in = new Scanner(System.in);
		n = in.nextInt();
		s = in.nextInt();
		arr = new int[n];
		for (int i = 0; i < n; i++) {
			arr[i] = in.nextInt();
		}
		left = new ArrayList<Integer>();
		right = new ArrayList<Integer>();

		findAllSums(0, 0, n / 2, left);
		findAllSums(0, n / 2, n, right);

		Collections.sort(left);
		Collections.sort(right);
		int leftIndex = 0;
		int rightIndex = right.size() - 1;
		while (leftIndex < left.size() && rightIndex >= 0) {
			int leftSum = left.get(leftIndex);
			int rightSum = right.get(rightIndex);

			if (leftSum + rightSum == s) {
				long leftSame = 0;
				while (leftIndex < left.size() && left.get(leftIndex) == leftSum) {
					leftIndex++;
					leftSame++;
				}
				long rightSame = 0;
				while (rightIndex >= 0 && right.get(rightIndex) == rightSum) {
					rightIndex--;
					rightSame++;
				}
				ans += leftSame * rightSame;
			} else if (leftSum + rightSum < s) {
				// 찾으려고 하는 수는 더 크기 때문에 left를 오른쪽으로 한 칸 움직여준다.
				leftIndex++;
			} else {
				// 마찬가지로 rightIndex 한칸 왼쪽으로 움직여준다.
				rightIndex--;
			}
		}

		if (s == 0) {
			ans -= 1;
		}

		System.out.println(ans);
	}

	public static void findAllSums(int sum, int index, int end, ArrayList<Integer> list) {
		if (index == end) {
			list.add(sum);
			return;
		}

		findAllSums(sum + arr[index], index + 1, end, list);
		findAllSums(sum, index + 1, end, list);
	}
}

 

 

 

'알고리즘 공부 > boj' 카테고리의 다른 글

boj 2632: 피자판매  (0) 2020.07.15
boj 7453: 합이 0인 네 정수  (0) 2020.07.13
boj 1956: 운동  (0) 2020.07.10
boj 1507: 궁금한 민호  (0) 2020.07.10
boj 11780: 플로이드2  (0) 2020.07.09

+ Recent posts