본문 바로가기

알고리즘 스터디

[JAVA + Python] BOJ 2981 검문

728x90

출처 : 백준

 

왜 정답 비율이 저렇게 낮은지 알법한 문제였다. 처음엔 유클리드 호제법을 알지 못한 체 무작정 최대 공약수 구하다 보니 시간 초과가 정말 괴롭게 했다..

 

수학적으로 접근하는 방법도 있지만 필자는 숫자들의 패턴을 보고 알고리즘에 접근했다. 예를 들어

 

N=2, 주어진 입력값은 [2, 12] 라고 할 때 M은 2, 5, 10이다 이를 보고 알아낸 것은 같은 M을 가지려면 두 수의 차의 약수를 구하면 되는구나라고 생각했다. 12-2 = 10이고 10의 공약수는 1을 뺀 2, 5, 10이 되기 때문이다. 

 

만약 N=3 이고  2, 12, 18 가 주어진다면 M은 2 뿐이다. 2와 12의 차이는 10이고 18과 12의 차이는 6이기 때문에 10과 6의 최대 공약수는 2이고 최대 공약수의 약수 중 1을 제외하면 2만 남는다.  

 

이 패턴을 찾아내는데 꽤 많은 시간을 쓴 것 같다. 수학적으로 접근할 줄 알았으면 훨씬 빨랐을 텐데 아쉽다..

 

a라는 숫자와 b라는 숫자가 주어지고 같은 나머지 값을 같는다고 하면 다음과 같다.

a = M*p + r

b = M*q + r

 

같은 r이기 때문에 b-a = M(q-p)이고 M은 (b-a)의 공약수이다. 앞선 예제처럼 a=2, b=12라고 하면 M 은 12-2의 약수 들이었다. 

 

문제에선 a, b 두 숫자만 주어지지 않고 여러 숫자가 주어진다. N=5 이고 a, b, c, d, e가 주어진다면

((b-a)의 약수, (c-b)의 약수, (d-c)의 약수, (e-d)의 약수) 의 약수를 구하면 된다. 즉 최대공약수를 구해 그 최대공약수의 약수를 구하면 된다.

 

(b-a)와 (c-b)의 최대공약수(g1) 를 구하고 (d-c)와 g1의 최대공약수를 구하는 과정을 이어가면서 최종 g1의 약수들을 출력하면 된다.   

 

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

public class Main {
	public static void main(String[] args) throws IOException{
		BufferedReader br= new BufferedReader(new InputStreamReader(System.in));
		BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(System.out));
		
		StringTokenizer st = new StringTokenizer(br.readLine());
		int N = Integer.parseInt(st.nextToken());
		int[] arr = new int[N];
		for(int i=0; i<N;i++) {
			st = new StringTokenizer(br.readLine());
			arr[i] = Integer.parseInt(st.nextToken());
		}
		Arrays.sort(arr);
		int gcd_ = arr[1]-arr[0];
		for(int i=2;i<N;i++) {
			gcd_ = gcd(gcd_, arr[i]-arr[i-1]);
		}
		for(int i=2;i<=gcd_;i++) {
			if(gcd_%i==0) bw.write(i+" ");
		}
		bw.flush();
		bw.close();
	}
	public static int gcd(int a, int b) {
		if(b==0) return a;
		return gcd(b, a%b);
	}
}

 

최대공약수는 gcd 라는 유클리드 호제법을 바탕으로 구현한 메서드를 통해서 구하고 각 입력값의 차가 음수가 되는 것을 방지하기 위해 arr을 오름차순으로 정렬해주었다. 이후 모든 케이스의 최대공약수(gcd_)를 구해 gcd_의 약수를 출력하였다.

 

 

+같은 알고리즘을 가지고 파이썬으로도 구현해보았는데 역시나,, python3는 시간 초과를 뱉고 Pypy3는 통과를 하였다.

def gcd(a,b):
    if b==0:
        return a
    return gcd(b, a%b)
N = int(input())

li = []
for i in range(N):
    li.append(int(sys.stdin.readline()))

li.sort()

gcd_ = li[1]-li[0]
for i in range(2, N):
    gcd_ = gcd(gcd_, li[i]-li[i-1])
    
for i in range(2, gcd_+1):
    if gcd_%i ==0:
        print(i, end=" ")

'알고리즘 스터디' 카테고리의 다른 글

[Python] BOJ 1010 다리놓기  (0) 2021.07.20
[Python] BOJ 11051 이항 계수2  (0) 2021.07.19
[JAVA + Python] BOJ 1934 최소공배수  (0) 2021.07.17
[JAVA] BOJ 13305 주유소  (0) 2021.07.15
[JAVA] BOJ 1541 잃어버린 괄호  (0) 2021.07.14