약수
| 2의 약수 | 8의 약수 | 9의 약수 |
|---|---|---|
| 2 / 1 = 2 | 8 / 1 = 8 | 9 / 1 = 9 |
| 2 / 2 = 1 | 8 / 2 = 4 | 9 / 3 = 3 |
| 8 / 4 = 8 | 9 / 9 = 1 | |
| 8 / 8 = 1 |
소수
| 소수 | 소수 | 소수 | 소수 | 소수 |
|---|---|---|---|---|
| 2 / 1 = 2 | 3 / 1 = 3 | 5 / 1 = 5 | 7 / 1 = 7 | 11 / 1 = 11 |
| 2 / 2 = 1 | 3 / 7 = 1 | 5 / 5 = 1 | 7 / 7 = 1 | 11 / 11 = 1 |
[실습] 1부터 30까지의 숫자 중 5로 나눈 몫과 나머지가 모두 소수인 숫자들을 찾아보자
[실습] 1부터 30까지의 숫자 중 소수를 찾아보자.
1~30까지 중 각 소수 본인을 제외한 소수의 배수를 제거
1. 2를 제외한 2의 배수 제거
2. 3을 제외한 3의 배수 제거
3. 5를 제외한 5의 배수 제거
4. 7을 제외한 7의 배수 제거
5. 11을 제외한 11의 배수 제거
6. ...
파이썬을 이용해서 사용자가 입력한 숫자의 약수를 출력해보자.
inputNumber = int(input('0보다 큰 정수 입력: '))
for number in range(1, (inputNumber+1)): # 사용자가 입력한 숫자까지 돌아가야/반복이 되어야 하니 +1
if inputNumber % number == 0: # 숫자를 나눈 나머지가 0이라면 = 나누어떨어진다면
print('{}의 약수: {}'.format(inputNumber, number))

# 파이썬을 이용해서 사용자가 입력한 숫자까지의 소수를 출력해보자.
inputNumber = int(input('0보다 큰 정수 입력: '))
for number in range(2, (inputNumber+1)): #1은 소수에서 제외하기 때문에 2에서부터 출발하면 된다.
flag = True # 일단 flag 변수에다 True 논리형 자료 저장
# 이제 1과 자기자신 외에 다른 약수가 존재하는지 아닌지 판단
for n in range(2, number): # 중첩 for문을 반복시키는데, 이 때엔 들어온 그 number까지만 반복
if number % n == 0: # 반복을 하다가 n으로 나눈 나머지가 0이라면
flag = False # 그러면 1과 자신 외의 약수가 있다는 의미이니, flag=False로 바꾼다
break # 그리고 반복문을 종료한다
# 예) 만약 4가 들어왔다면, 1부터 자기자신(4) 사이에 약수가 존재해선 안 된다
# 4같은 경우는 2가 약수로 있다; 따라서 flag=False로 바꿔준다
# 반면, 5는 1과 5 사이에 2, 3, 4가 있지만 나누어떨어지는 수가 없다; 따라서 그대로 flag=True
# flag=True가 나오면 소수; flag=False는 합성수(1과 본인 자신외에 또 다른 약수를 가지고 있는 수)
if (flag):
print('{}: 소수'.format(number))
else:
print('{}: 합성수'.format(number))

소인수
소인수분해
소인수분해와 약수
- 20의 소인수분해 -> 2^2 x 5
- 5같은 경우 약수가 1, 5 / 4(2^2) 같은 경우 1, 2, 4
- 이것을 행과 열 테이블 형태로 정렬하고
| 1 | 5 | |
|---|---|---|
| 1 | 1 | 5 |
| 2 | 2 | 10 |
| 2^2 | 4 | 20 |
--> 여기서 각 행과 열을 곱하면 20의 각각의 약수가 나온다.
--> 1x1= 1 | 1x2 = 2 | 1x2^2 = 4 | 5x1 = 5 | 5x2 = 10 | 5x2^2 = 20 |
[실습] 다음의 수를 소인수분해를 통해서 약수를 구해보자.
# 파이썬을 이용해서 사용자가 입력한 수를 소인수분해하자.
inputNumber = int(input('1보다 큰 정수 입력: '))
n = 2 #소인수가 될 변수
while n <= inputNumber: # 2에서 사용자가 입력한 숫자까지 반복문 실행; 입력한 숫자가/에서 1이 될 때까지 반복문 실행
if inputNumber % n == 0: # 사용자가 입력한 숫자가 2(또는 n)로 나누어떨어진다면
print('소인수: {}'.format(n)) # 일단 그 2(또는 n)은 빼내고('소인수: n' 출력)
inputNumber /= n # inputNumber를 2(또는 n)으로 나눈 몫을 다시 inputNumber로 할당
# 그리고 그 inputNumber에 대한 반복문을 또 진행
# 2(또는 n)로 나눈 나머지가 0이 아닌경우 n은 +1 증가하고 다음 단계/반복 실행
else:
n += 1
# 만약 입력한 수 inputNumber가 12라면, 2로 나누면 나머지가 0이 나올 텐데,
# 이런 경우, 2를 일단 빼낸다/출력한다; (2는 소인수; 소인수 2 1개)
# 그 다음, inputNumber를 2로 나누면 몫이 6일 것이고, 그러면 그 6을 inputNumber에 할당
# 그리고 이어서, 이번엔 inputNumber에 할당된 6을 가지고 반복문 진행
# 6을 다시 2로 나누면 3으로 나누어떨어지니 이 2도 소인수('소인수 2' 출력; 소인수 2 2개),
# 6을 2로 나눈 몫 3을 다시 inputNumber에 할당
# 또 이번엔 3에 대한 반복문 진행되는데, 이번엔 3을 2로 나누면 나머지가 0이 안된다(나누어떨어지지 않는다)
# 그렇다면 else문이 실행이 될 것이고 n = n+1이 되어 n=3이 된다
# n=3을 가지고 반복문이 또 실행되고, 이번엔 3(inputNumber) / 3(n)으로 나눈 나머지가 0이 되기에(나누어떨어지기에)
# 3은 소인수; 그럼 '소인수: 3'을 출력(소인수 3 1개)하고,
# (inputNumber = inputNumber / n)을 거쳐 --> 3/3 = 1 --> inputNumber=1이 되며
# n <= inputNumber가 성립이 안 되기에 반복문은 종료
# 결과적으로, 소인수 2, 3을 찾았고 출력하게 된 것이다.

# 72에 x를 곱하면 y의 제곱이 된다고 할 때, x에 해당하는 가장 작은 정수를 구하자.
# 2 x 2 x 2 x 3 x 3 x X = Y^2
# => 2^3 x 3^2 x X = Y^2
# => 2^2 x 2 x 3^2 x X = Y^2
# 2^2 x 2 x 3^2가 ( )^2으로 묶을 수 있을 것 같은데 => 2^2 x 2^2 x 3^2 가 되면 ( )^2로 묶일 수 있다.
# 따라서, 2^2 x 2 x 3^2에 곱해야 할 X는 2가 되며, Y^2 에서 Y는 12가 된다.
inputNumber = int(input('1보다 큰 정수 입력: '))
n = 2
searchNumbers = [] # 이 리스트에 소인수 숫자들을 넣을 건데,
# 갯수가 짝수가 안 되는 숫자는 거듭제곱이 안 되니 하나 더 넣어줄 것이다
while n <= inputNumber:
if inputNumber % n == 0:
print('소인수: {}'.format(n))
# 소인수 개수가 짝수가 아닌 소인수 찾기
if searchNumbers.count(n) == 0: # n의 개수가 0이면; list.count(): 해당 리스트에 n이 몇개가 있는지 반환
searchNumbers.append(n) # 그 n을 리스트에 추가
elif searchNumbers.count(n) == 1: # n이 하나라면
searchNumbers.remove(n) # 해당 n은 리스트에서 제거
inputNumber /= n
else:
n += 1
print('searchNumbers: {}'.format(searchNumbers))
# 반복문이 돌아가면서, 처음 소인수 2가 search list에 추가될 것이고, 그리고 다음 반복문에서 소인수 2가 리스트에 1개 있으니,
# 해당 소인수를 리스트에 제거 (--> 1개 +, 1개 - 된 것이니, 여기까진 개수가 짝수이다)
# 그리고 또 반복문 실행되면서, 소인수 2가 리스트에 있는지 조회되며, 이미 리스트에서 지웠으니, 당연히 0개
# 그러면 소인수 2는 또 리스트에 추가된다. 하지만 이후엔, 더 이상 소인수 2가 없다; 리스트엔 소인수 2 1개가 남아있다.
# 따라서, 소인수 2는 짝이 없는 것이니, 결국 소인수 2는 개수가 홀수라는 뜻
# 그렇다면, 72에 곱해야 할 x는 '2'

공약수
ex)
12의 약수: 1,2,3,4,6,12
20의 약수: 1,2,4,5,10,20
12와 20의 공통된 약수: 1,2,4 (공약수)
최대공약수
ex)
12의 약수: 1,2,3,4,6,12
20의 약수: 1,2,4,5,10,20
공약수: 1,2,4
최대공약수: 4
12의 소인수분해: 2^2 x 3
20의 소인수분해: 2^2 x 5
이 중 공통된 숫자가 있다 : 2^2
(거듭제곱 중에 지수의 밑이 같은 것)
=> 공통된 숫자 4(2^2)가 12와 20의 최대공약수가 된다
*만약 밑은 같은데 지수가 다른 것이 있다면(e.g. 2^1 vs. 2^2), 지수가 작은 2^1을 채택한다.
최대공약수를 구했으면, 4에 대한 약수를 구한다: 1, 2, 4
이 1,2,4 약수가 12와 20의 공약수가 된다.
2 | 36 60
2 | 18 30
3 | 9 15
--------
3 5
--> 2 x 2 x 3 = 12 (36와 60의 최대공약수)
--> 12의 약수: 1,2,3,4,6,12 (36와 60의 공약수)
[실습] 다음 수의 최대공약수 및 공약수를 구해보자.
[실습] 빵 112개와 우유 80개를 학생들한테 남김없이 동일하게 나누어 주려고 할 때, 최대 몇 명의 학생이 빵과 우유를 받을 수 있는지 계산해 보자.
그리고, 학생 한 명이 받게되는 빵과 우유의 개수를 계산해 보자.
# 두 개의 수를 입력하면 공약수와 최대공약수를 출력하는 코드를 작성하자.
# 단, 두 번째 입력하는 수가 첫 번째 입력하는 수보다 크다.
num1 = int(input('1보다 큰 정수 입력: '))
num2 = int(input('1보다 큰 정수 입력: '))
maxNum = 0
for i in range(1, (num1 + 1)): # num1이 더 작다는 전제하에, num1까지 반복 설정; 우리는 공통된 약수를 구하는 것이기 때문에, num1보다 큰 것은 의미가 없다
if num1 % i == 0 and num2 % i == 0: # 첫번째 숫자와 두번째 숫자를 i로 나눈 나머지가 0인 경우 = 공약수
print('공약수: {}'.format(i))
maxNum = i # 최대공약수; 반복문이 돌아가면서 공약수 i가 계속 나올때마다 maxNum에 할당; 그럼 점점 큰 공약수가 할당 될 테고, 끝에 할당 된 것이 최대공약수
print('최대공약수: {}'.format(maxNum))

# 세 개의 수를 입력하면 공약수와 최대공약수를 출력하는 코드를 작성하자.
# 바로 위 문제와 비슷하다.
num1 = int(input('1보다 큰 정수 입력: '))
num2 = int(input('1보다 큰 정수 입력: '))
num3 = int(input('1보다 큰 정수 입력: '))
maxNum = 0
for i in range(1, (num1 + 1)):
if num1 % i == 0 and num2 % i == 0 and num3 % i == 0:
print('공약수: {}'.format(i))
maxNum = i
print('최대공약수: {}'.format(maxNum))

유클리드 호제법
x y r
1. 12 % 36 = 12
2. 36 % 12 = 3 # 두번째에 놓인 숫자 36을 앞으로 가져오고, 나머지인 12도 앞으로 가져온다; 그래서 또 나눈다
3. 12 % 3 = 0 # 그러면 또 두번째 숫자 12를 앞으로 가져오고, 나머지인 3도 앞으로 가져와 나눈다 --> 이렇게 나머지가 0이 될 때가지 나눈다
4. ... # 나머지가 0이 나오는 시점의 두번째에 나오는 수(여기선 3)가 최대공약수가 된다.
# 유클리드 호제법을 이용해서 최대공약수를 구해보자.
num1 = int(input('1보다 큰 정수 입력: '))
num2 = int(input('1보다 큰 정수 입력: '))
temp1 = num1; temp2 = num2
# 최대공약수 구하기
while temp2 > 0:
temp = temp2 # temp2(y)를 일단 임시로 temp라는 변수에 저장
temp2 = temp1 % temp2 # temp1(x)를 temp2(y)로 나눈 나머지(r)을 다시 temp2에 할당하여 앞으로 당겨오기
temp1 = temp # 나누기가 끝나면 temp에 저장된 y를 temp1으로 할당해서 앞으로 당겨온다
# 반복문이 계속 되면서 temp1 % temp2 나눈 나머지(r)가 0이 되는 시점이 온다; 그럼 temp2=0이 되며 반복문은 종료된다.
# 이때, 마지막으로 두번째 수 temp2(y)에 할당된 y값이 최종적으로 temp1에 저장되며, 최대공약수 출력 (print(temp1))
print('{}, {}의 최대공약수: {}'.format(num1, num2, temp1))
# 구해진 최대공약수의 약수를 구하면 num1과 num2의 공약수가 된다.
for n in range(1, (temp1 + 1)):
if temp1 % n == 0:
print('{}, {}의 공약수: {}'.format(num1, num2, n))

공배수
ex)
3의 배수: 3,6,9,12,15,18,...
5의 배수: 5,10,15,20,25,...
공통된 배수(공배수): 15,30,...
최소공배수
ex)
3의 배수: 3,6,9,12,15,18,...
5의 배수: 5,10,15,20,25,...
공통된 배수(공배수): 15,30,...
그 중 가장 작은 수(최소공배수): 15
4의 소인수분해: 2^2
12의 소인수분해: 2^2 x 3
최소공배수:
--> 공통인 소인수의 거듭제곱에서 지수가 크고 공통아닌 수를 모두 곱한다.
--> 2^2는 공통; 3은 공통이 아니지만 모두 곱한다
--> 최소공배수: 2^2 x 3 = 12가 된다.
공배수:
--> 12의 배수(12, 24, 36,...)
- num1, num2 두 수의 최대공약수가 num3이라고 할 때, (num1 x num2)를 num3로 나눈 몫( (num1xnum2)//num3 )이 최소공배수가 된다
2 | 6 12
2 | 3 6
--------
1 2
--> 2 x 2 x 1 x 2 한다
--> 2^2 x 3 = 12 (6과 12의 최소공배수)
--> 12의 배수: 12,24,36,... (6과 12의 공배수)
[실습] 다음 수의 최소공배수 및 공배수를 구해보자.
[실습] 2,5,8의 하나만 제외하고 나머지 두 개의 수는 5를 곱하여도 최소공배수에 변함이 없다. 5를 곱하였을 때 최소공배수에 변함이 있는 수를 찾아보자.
# 두 개의 수를 입력하면 최소공배수를 출력하는 코드를 작성하자.
num1 = int(input('1보다 큰 정수 입력: '))
num2 = int(input('1보다 큰 정수 입력: '))
maxNum = 0
# 일단 최대공약수를 구한다
for i in range(1, (num1 + 1)):
if num1 % i == 0 and num2 % i == 0:
print('공약수: {}'.format(i))
maxNum = i
print('최대공약수: {}'.format(maxNum)) # 여기까진 최대공약수 구하는 로직
minNum = (num1 * num2) // maxNum # 두 수를 곱한 것을 두 수의 최대공약수로 나눈 몫이 최소공배수가 된다
print('최소공배수: {}'.format(minNum))

# 세 개의 수를 입력하면 최소공배수를 출력하는 코드를 작성하자.
# 두 개의 수에 대한 최소공배수를 먼저 구한 후, 세 번째 수의 공배수를 구한다.
# --> 두 개의 수에 대해서 최소공배수 구하고, 그 최소공배수와 세 번째 수의 최소공배수를 구하면 세개 수의 최소공배수를 구할 수 있다
num1 = int(input('1보다 큰 정수 입력: '))
num2 = int(input('1보다 큰 정수 입력: '))
num3 = int(input('1보다 큰 정수 입력: '))
maxNum = 0
# 우선 두 개 수의 최대공약수를 구하고 그것으로 최소공배수를 구한다.
for i in range(1, (num1 + 1)):
if num1 % i == 0 and num2 % i == 0:
maxNum = i
print('최대공약수: {}'.format(maxNum)) # 두 개 수의 최대공약수
minNum = (num1 * num2) // maxNum # 두 개 수의 최소공배수
print('{}, {}의 최소공배수: {}'.format(num1, num2, minNum))
# 그렇게 구해진 최소공배수와 세번째 숫자를 가지고 (위와 동일한 로직 사용하여) 최대공약수와 최소공배수를 구하면 된다.
newNum = minNum
for i in range(1, (newNum+1)):
if newNum % i == 0 and num3 % i == 0:
maxNum = i
print('최대공약수: {}'.format(maxNum)) # (num1, num2의 최소공배수)와 (num3)의 최대공약수
minNum = (newNum * num3) // maxNum # (num1, num2의 최소공배수)와 (num3)의 최소공배수 = 세 개 숫자의 최소공배수
print('{}, {}, {}의 최소공배수: {}'.format(num1, num2, num3, minNum))

# 섬마을에 과일, 생선, 야채를 판매하는 배가 다음 주기로 입항한다고 할 때, 모든 배가 입항하는 날짜를 계산해 보자.
# 과일 선박: 3일 주기 / 생선 선박 : 4일 주기 / 야채 선박 : 5일 주기
ship1 = 3; ship2 = 4; ship3 = 5
maxDay = 0
for i in range(1, (ship1+1)):
if ship1 % i == 0 and ship2 % i == 0:
maxDay = i
print('최대공약수: {}'.format(maxDay))
minDay = (ship1 * ship2) // maxDay
print('{}, {}의 최소공배수: {}'.format(ship1, ship2, minDay))
newDay = minDay
for i in range(1, (newDay+1)):
if newDay % i == 0 and ship3 % i == 0:
maxDay = i
print('최대공약수: {}'.format(maxDay))
minDay = (newDay * ship3) // maxDay
print('{}, {}, {}의 최소공배수: {}'.format(ship1, ship2, ship3, minDay))

진법이란?
2진법 --> 0 1 (2개 사용)
8진법 --> 0 1 2 3 4 5 6 7 (8개 사용)
10진법 --> 0 1 2 3 4 5 6 7 8 9 (10개 사용)
16진법 --> 0 1 2 3 4 5 6 7 8 9 A B C D E F (16개 사용); 참고로, 알파벳은 소문자여도 오케이
10진수를 X진수로 변환
X진수를 10진수로 변환
- 2진수 --> 10진수

- 8진수 --> 10진수

2진수를 8진수로 변환
- 2진수 --> 8진수

- 2진수 --> 16진수

# 10진수를 X진수로 변환
# 10진수 --> 2진수, 8진수, 16진수
'''
binary: bin() --> 2진수로 변환
octal: oct() --> 8진수로 변환
Hexadecimal: hex() --> 16진수로 변환
2진수: 0b1110
8진수: 0o36
16진수: 0x1e
'''
dNum = 30
print('2진수: {}'.format(bin(dNum)))
print('8진수: {}'.format(oct(dNum)))
print('16진수: {}'.format(hex(dNum)))
# 결과는 항상 문자열(str)이다
# 다른 진수 변환/출력 방법 1
print('2진수: {}'.format(format(dNum, '#b')))
print('8진수: {}'.format(format(dNum, '#o')))
print('16진수: {}'.format(format(dNum, '#x')))
# 다른 진수 변환/출력 방법 2
print('{0:#b},{0:#o},{0:#x}'.format(dNum))
# 앞에 상징적인 의미 없이 출력하고자 한다면
print('2진수: {}'.format(format(dNum, 'b')))
print('8진수: {}'.format(format(dNum, 'o')))
print('16진수: {}'.format(format(dNum, 'x')))
# 결과는 항상 문자열(str)이다

# x진수 --> 10진수
print('2진수(0b11110) --> 10진수({})'.format(int('0b11110', 2))) # 이렇게 int()함수에다 문자열과 진수를 입력해 주면 int내부적으로 진수를 변환해서 출력;
print('8진수(0o36) --> 10진수({})'.format(int('0o36', 8))) # 이 문자열은 8진수입니다 라는 걸 알려주는 것
print('16진수(0x1e) --> 10진수({})'.format(int('0x1e', 16)))

# x진수 --> x진수
2진수로 변경: bin() 사용 # 각 함수 안에는 문자열(0b11110, 0p36 등 입력)
8진수로 변경: oct() 사용
10진수로 변경: int() 사용
16진수로 변경: hex() 사용
수열이란?
항이라고 한다. 1항, 2항, 3항,... an

특정항은 특정항까지의 합에서 특정항 이전의 항까지의 합과 같다.

[실습] 다음 수열의 일반항을 구해보자.


등차수열
2 4 6 8 10 12 14 16
- 2씩 차이/증가하는 --> "두 항의 차이가 2인 등차 수열"
- 차이가 나는 값/수인 2 --> 공차(d) 라고 부른다

등차 중항
등차 수열의 합

[실습] 다음 수열의 일반항을 구해보자.

[실습] 다음 수열에서 a2과 a6의 등차 중항을 구해보자.

# 다음 수열을 보고 n번째 항의 값을 출력하는 프로그램을 만들어보자.
'''
an = {2, 5, 8, 11, 14, 17, 20, ...}
'''
inputN1 = int(input('a1 입력: ')) # 첫번째항 입력
inputD = int(input('공차 입력: ')) # 공차 입력
inputN = int(input('n 입력: ')) # 알고싶어하는 n번째 항에 대한 n 입력
valueN = 0 # n번째 항의 값을 valueN이라는 변수를 사용하겠다고 선언하고; 일단은 0
n = 1 # 첫번째 항부터 시작을 하기에
while n <= inputN: # 사용자가 알아내고자 하는 n번째 항까지 반복
if n == 1: # n이 1인 경우/첫번째 항인 경우에는
valueN = inputN1 # 사용자가 입력한 첫번째 항 값을 valueN에 할당;
print('{}번째 항의 값: {}'.format(n, valueN)) # "n번째 항의 값은 valueN이다"
n+=1 # 그리고 n에다가 1을 더해주고 다시 올라간다
continue # n은 이제 2이기 때문에, 이제 이 반복문의 역할을 끝났고 이 아래의 구문이 실행된다
valueN += inputD # valueN에는 현재 1항의 값이 들어있는데, 이 첫번째 항의 값에다가 사용자가 입력한 공차(d)를 더해준다; 그럼 두번째 항의 값이 나오겠고
print('{}번째 항의 값: {}'.format(n, valueN))
n += 1 # n + 1 되고 다시 위로 올라가서 다시 반복 실행;
# 그럼 세번째 항을 구하게 될 텐데, 2항까지의 숫자에 공차(d)를 더해주면 된다
# 계속 이렇게 나가다보면 (입력한) n번째 항의 값을 구할 수 있겠다.
print('{}번째 항의 값: {}'.format(inputN, valueN))

## 다음 수열을 보고 n번째 항의 값을 출력하는 프로그램을 만들어보자.
'''
an = {2, 5, 8, 11, 14, 17, 20, ...}
'''
# 등차 수열(일반항) 공식: an = a1 + (n-1) * d
# 이번엔 이 공식을 이용해서 프로그램 만들기
inputN1 = int(input('a1 입력: ')) # 첫번째항 입력
inputD = int(input('공차 입력: ')) # 공차 입력
inputN = int(input('n 입력: ')) # 알고싶어하는 n번째 항에 대한 n 입력
valueN = inputN1 + (inputN-1) * inputD
print('{}번째 항의 값: {}'.format(inputN, valueN))
# 공식을 사용하면 더 간단하게 구할 수 있다.
