백준 1010 - 다리 놓기

Updated:

Java

1010 번 - 다리 놓기

문제

재원이는 한 도시의 시장이 되었다. 이 도시에는 도시를 동쪽과 서쪽으로 나누는 큰 일직선 모양의 강이 흐르고 있다. 하지만 재원이는 다리가 없어서 시민들이 강을 건너는데 큰 불편을 겪고 있음을 알고 다리를 짓기로 결심하였다. 강 주변에서 다리를 짓기에 적합한 곳을 사이트라고 한다. 재원이는 강 주변을 면밀히 조사해 본 결과 강의 서쪽에는 N개의 사이트가 있고 동쪽에는 M개의 사이트가 있다는 것을 알았다. (N ≤ M)

재원이는 서쪽의 사이트와 동쪽의 사이트를 다리로 연결하려고 한다. (이때 한 사이트에는 최대 한 개의 다리만 연결될 수 있다.) 재원이는 다리를 최대한 많이 지으려고 하기 때문에 서쪽의 사이트 개수만큼 (N개) 다리를 지으려고 한다. 다리끼리는 서로 겹쳐질 수 없다고 할 때 다리를 지을 수 있는 경우의 수를 구하는 프로그램을 작성하라.

접근 방법

고등학교 수학시간에 풀었던 조합 문제를 떠올리면 된다.
조합은 집합에서 서로 다른 n개의 원소 중에서 순서에 상관없이 r개를 선택하는 것이다.이라고 한다.
이를 문제에 적용하면, 서로 다른 n개의 동쪽 사이트에서 r개 서쪽 사이트를 뽑는 것이 된다.

구현

조합을 구하는 공식은
이다.
간단한 문제이지만, 문제는 문제 조건이 최대 30C15의 경우, long형은 이미 overflow가 된다.
따라서 2가지 방법으로 꼼수를 썼는데,

  1. 30C2030C10와 같아, 최대한 r을 줄여준다.
  2. 계산은 결국, 분자를 분모로 나누는 것이므로 분자를 곱하고, 분모를 곱하여 두개를 나누어준다.
    여기서, 분자를 구하는 경우에 long 최대 값을 넘을 수 있으므로 분자를 구하는 도중, 미리 구한 분모로 한번 나누어 overflow를 방지한다

코드

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

public class Main {
	static int n,m,tc, sel[];
	public static void main(String[] args) throws IOException {
		BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
    	StringTokenizer stk;
    	
    	tc = stoi(br.readLine());
    	StringBuilder sb = new StringBuilder();
    	while(tc-- != 0) {
    		long result = 1;
    		long divide = 1;
    		stk = new StringTokenizer(br.readLine());
    		n = stoi(stk.nextToken());
    		m = stoi(stk.nextToken());

			// 30C26 와 같은 경우, 30C4와 같으므로 n 수를 줄여준다
    		if(n > m / 2) {
    			n = m - n;
    		}
			// 분모를 미리 곱한다.
    		for(int i = n; i >= 1; i--) {
    			divide *= i;
    		}
    		for(int i = m; i > m - n; i--) {
    			result *= i;		// 분자를 곱한다
				// [C / K] 라고 할때, C가 K보다 크고, C가 K의 나누어 떨어지면, 미리 나누어준다.
				// 위와 같은 방법으로 C가 long 형 최대 값을 초과하는 것을 방지한다.
    			if(result >= divide && result % divide == 0) {
    				result /= divide;
    				divide = 1;
    			}
    		}
    		
    		sb.append(result).append("\n");
    	}
    	System.out.println(sb);	
    	br.close();
	}
	
	static int stoi(String str) {
    	return Integer.parseInt(str);
    }
}

총평

난이도

⭐⭐★★★

후기

개선할 점