알고리즘 수학(나머지 연산, 최대 공약수, 최소 공배수)
본문 바로가기
알고리즘 최종 (단계별)/1.수학

알고리즘 수학(나머지 연산, 최대 공약수, 최소 공배수)

by KyeongMin 2023. 6. 25.
728x90
반응형

나머지 연산

  • (A + B) % C === ((A%C) + (B%C)) %C
  • (A * B) % C === ((A%C) * (B%C)) %C
  • (A - B ) % C === (( A % C ) - (B %C) + C) %C
    • 뺄셈의 경우 음수가 나올 수 있어서 C를 더함

10430_나머지

  • 문제링크

https://www.acmicpc.net/problem/10430

#include <stdio.h>
#include <vector>
#include<iostream>
using namespace std;
int A, B, C;
int main(void) {
	cin >> A >> B >> C;
	cout << (A + B) % C << '\\n';
	cout << ((A%C) + (B%C)) % C << "\\n";
	cout << (A*B) % C << "\\n";
	cout << ((A%C) *(B%C)) % C << "\\n";
	return 0;
}

최대 공약수

  • GCD라고 함
    • 두 수 A와 B의 최대 공약수는 G는 A와 B의 공통된 약수 중에서 가장 큰 정수
    • 최대 공약수를 구하는 쉬운 방법
      • 2 부터 min(A,B)까지 모든 수 나눠보면 됨
      • 최대 공약수가 1인 두 수를 서로소 라고 함
int g = 1;
for (int i=2; i<=min(a,b); i++){
	if( a % i == 0 && b % i == 0) {
		g =i;
	}
}
  • 위와 같은 구현하는 경우 시간 복잡도 O(N)이 걸림
  • 그럼 더 빠르게 구현하는 방법은 뭘까?
    • 유클리드 호제법을 사용하면 된다.
      • Euclidean algorithm

유클리드 호제법

  • a를 b로 나눈 나머지를 r이라고 했을때
  • GCD(a,b) = GCD(b,r)과 같음
    • 이때, r 이 0 이면 b가 최대 공약수임
  • ex) GCD(24,16) = GCD(16,8) = GCD(8,0) = 8

재귀를 사용하지 않는 방법

// 그냥 베이직 
int main() {
	int a, b;
	cin >> a >> b;

	while (b!=0) {
			int r = a % b;
			a = b;
			b = r;
	}

	cout << a;
	return 0;
}

//함수로 분리

int gcd(int a, int b) {
	while (b != 0) {
		int r = a % b;
		a = b;
		b = r;
	}
	return a;
}

재귀를 사용하는 방법

int GCD_re(int a, int b) {
	if (b == 0) return a;
	return GCD_re(b, a%b);
}

세 수의 최대 공약수

GCD(a,b,c) = GCD(GCD(a,b),c)

최소 공배수

  • LCM이라고함
  • 두 수의 최소 공배수는 두수의 공통된 배수에서 가장 작은 정수
  • 최소 공배수는 최대공약수를 이용함

최소 공배수 = l = GCD(a,b) * (a/GCD(a,b)) * (b/GCD(a,b)

2609_최대공약수와 최소공배수 문제 풀어보기

  • 문제 링크

https://www.acmicpc.net/problem/2609

#include<stdio.h>
#include<iostream>
using namespace std;

int GCD_re(int a, int b) {
	if (b == 0) return a;
	return GCD_re(b, a%b);
}

int gcd(int a, int b) {
	while (b != 0) {
		int r = a % b;
		a = b;
		b = r;
	}
	return a;
}

int main() {
	int num1, num2;
	cin >> num1 >> num2;
	/*while (b!=0) {
			int r = a % b;
			a = b;
			b = r;
	}*/
	int gcdNumber = GCD_re(num1, num2);
	cout << gcdNumber << '\\n';
	cout << gcdNumber * (num1 / gcdNumber)*(num2 / gcdNumber) << '\\n';
	return 0;
}

9613_GCD 합

  • 문제 링크

https://www.acmicpc.net/problem/9613

  • 문제 풀이 방식
    • 위 문제의 포인트는 GCD를 구할 줄 아는 것
    • 두개씩 쌍을 가지게 해서 GCD에 넣을 줄 알면됨
      • 무슨 말이냐면 완전 탐색을 해서 같은 위치의 숫자만 넣지 않으면 되는 것인데
      • 우리가 구해야하는 쌍은 아래와 같이 나타낼 수 있음
        • 즉, 위와 같이 같은 인덱스가 아닌것과 중복이 아닌것을 비교하면된다. 그래서아래와 같이 완전 탐색을 구현하면됨
        • for (int i = 0; i < n-1; i++) { for (int j = i + 1; j < n; j++) { sum += GCD(arr[i], arr[j]); } }
  • 소스코드
#include<stdio.h>
#include<iostream>
using namespace std;

int GCD(int num1, int num2) {
	if (num2 == 0) return num1;

	return GCD(num2, num1%num2);
}

int main(void) {
	int testCaseNumber;
	cin >> testCaseNumber;
	for (int tc = 0; tc < testCaseNumber; tc++) {
		int n = 0;		
		int arr[104] = { 0, };
		cin >> n;
		for (int i = 0; i < n; i++) {
			cin >> arr[i];
		}
		
		long long sum = 0;
		for (int i = 0; i < n-1; i++) {
			for (int j = i + 1; j < n; j++) {
				sum += GCD(arr[i], arr[j]);
			}
		}

		cout << sum << '\\n';
	}

	return 0;
}
  • 이런 정수의 합을 더하는 문제는 주의 할 것이 하나더 있음
    • 출력하는 것, 더하는 변수의 크기를 잘 지정해야함
    • 필자는 int로 습관적으로 했다가 엥? 뭐지 했었음
    • 이런 문제는 우선 입력 100개 이상이 넘는 합이기 때문에 정수 범위를 넘어갈 수 있음
      • 정확히 범위를 따지면 좋지만 힘들면 long long 정도만 해줘도 왠만한 문제는 통과함
728x90
반응형

'알고리즘 최종 (단계별) > 1.수학' 카테고리의 다른 글

소수 찾기 및 판별_심화  (0) 2023.07.05
소수_알고리즘 기본편  (0) 2023.07.04
진법 변환 - 심화  (0) 2023.06.28
진번 기초 문제  (0) 2023.06.27
알고리즘 진법 - 1 (기초)  (0) 2023.06.26

댓글