반응형
프로젝트 오일러.md

프로젝트 오일러 23번 문제


자신을 제외한 약수(진약수)를 모두 더하면 자기 자신이 되는 수를 완전수라고 합니다. 예를 들어 28은 1 + 2 + 4 + 7 + 14 = 28 이므로 완전수입니다. 또, 진약수의 합이 자신보다 작으면 부족수, 자신보다 클 때는 초과수라고 합니다.

12는 1 + 2 + 3 + 4 + 6 = 16 > 12 로서 초과수 중에서는 가장 작습니다. 따라서 초과수 두 개의 합으로 나타낼 수 있는 수 중 가장 작은 수는 24 (= 12 + 12) 입니다.

해석학적인 방법을 사용하면, 28123을 넘는 모든 정수는 두 초과수의 합으로 표현 가능함을 보일 수가 있습니다. 두 초과수의 합으로 나타낼 수 없는 가장 큰 수는 실제로는 이 한계값보다 작지만, 해석학적인 방법으로는 더 이상 이 한계값을 낮출 수 없다고 합니다.

그렇다면, 초과수 두 개의 합으로 나타낼 수 없는 모든 양의 정수의 합은 얼마입니까?



파이썬 코드

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
# -*- coding: utf-8 -*-
import math
 
#진약수를 모두 더한 값을 반환하는 함수
def divisors_sum(num):
    result = 0
    temp = math.sqrt(num)
       
    #n의 약수를 구할 때, 1부터 루트 n까지만 나눠본다. 나눠서 약수이면, n에서 해당 약수를 나눈 수도 약수이다.
    for i in range(1,int(temp)+1):
        if (num % i == 0):
            result += i + num/i
            if(temp == int(temp) and i == temp): #루트num 중복제거
                result -= i
    
    result -= num #자기자신을 뺀다
    return result
    
 
#num이 초과수이면 true, 아니면 false를 반환하는 함수
def Is_abundant_number(num):
    if(num < divisors_sum(num)): #num의 진약수의 합이 num보다 크면 초과수
        return True                                                                                       
    else:
        return False
        
abundant_list = [] #초과수를 저장할 리스트
sum_abundant_set = set() #2개의 초과수 합을 저장하는 집합
 
for n in range(12,28123):
    if(Is_abundant_number(n) == True): #n이 초과수이면 초과수 리스트(abundant_list)에 저장
            abundant_list.append(n)
    
 
#2개의 모든 초과수 합을 구함
for i in abundant_list:
    for j in abundant_list:
        if(i+< 28123):
            sum_abundant_set.add(i+j)
        
 
result = sum(range(1,28123)) - sum(sum_abundant_set)
print result
cs


풀이


초과수 리스트를 만든다. 초과수 리스트를 이용하여 2개의 초과 수 합 집합을 만든다. 집합을 사용한 이유는 자동으로 중복제거를 하기 위해서이다. 마지막으로 1부터 28123까지 합에서 2개의 초과 수 합을 빼면 답을 구할 수 있다. 

반응형
반응형
Untitled Document.md

프로젝트 오일러 22번 문제


여기 5천개 이상의 영문 이름들이 들어있는 46KB짜리 텍스트 파일 names.txt 이 있습니다 (우클릭해서 다운로드 받으세요). 이제 각 이름에 대해서 아래와 같은 방법으로 점수를 매기고자 합니다.

  • 먼저 모든 이름을 알파벳 순으로 정렬합니다.
  • 각 이름에 대해서, 그 이름을 이루는 알파벳에 해당하는 숫자(A=1, B=2, …, Z=26)를 모두 더합니다.
  • 여기에 이 이름의 순번을 곱합니다.

예를 들어 "COLIN"의 경우, 알파벳에 해당하는 숫자는 3, 15, 12, 9, 14이므로 합이 53, 그리고 정렬했을 때 938번째에 오므로 최종 점수는 938 × 53 = 49714가 됩니다.

names.txt에 들어있는 모든 이름의 점수를 계산해서 더하면 얼마입니까?





파이썬 코드

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
# -*- coding: utf-8 -*-
= open("E:/names.txt",'r')
= f.read()
f.close()
 
temp = s.split(',')
wordslist = [] #순수단어만 뽑아서 저장할 list
 
for words in temp: #단어 양옆에 "제거
    wordslist.append(words.strip('"'))
 
wordslist.sort() #단어를 알파벳 순으로 정렬
 
#알파벳에 해당하는 숫자(점수)
point = {'A':1'B':2'C':3'D':4'E':5'F':6'G':7'H':8'I':9'J':10'K':11'L':12'M':13'N':14'O':15'P':16'Q':17'R':18'S':19'T':20'U':21'V':22'W':23'X':24'Y':25'Z':26}
result = 0 #단어의 점수를 총합할 변수
words_point = 0 #각 단어의 점수를 저장할 변수
index = 1 #몇번째 단어인지 위치를 나타내는 변수
 
for words in wordslist:
    for alphabet in words:
        words_point += point[alphabet]
    result = result + words_point * (wordslist.index(words)+1#한 단어의 점수 합과 해당 단어의 위치를 곱한다
    words_point = 0
 
print result
cs





코드설명

파일을 읽어온다. 텍스트 파일에서 ,를 기준으로 단어를 나누어 리스트(temp)에 저장한다. 그 후, 단어양옆에 "을 제거하여 순수한 알파벳 단어만 남게하여 리스트(wordslist)에 저장한다.


리스트 내장함수 sort를 이용하여, 단어를 알파벳 순으로 정렬한다. 알파벳별 점수를 나타내는 point라는 사전을 만든다. 그 후, 리스트에서 단어를 하나씩 꺼내서 각 알파벳별 점수를 더한다. 그리고 정렬된 단어 순서를 곱하여 최종적인 점수를 구한다.


반응형
반응형
소수.md

소수 알고리즘


중학교 때 소수란 것을 배웠을 것이다. 양의 약수가 1과 자기 자신 뿐인 1보다 큰 자연수로 정의된다. 예를들면 2, 3, 5, 7, 11, 13…이 소수이다. 2는 유일한 짝수 소수이다. 소수를 구하는 방법들을 하나씩 알아보자.

1. N보다 작은 수로 나누어본다.


가장 생각하기 쉬운 방법이다. 소수의 성질을 이용하여, N을 2부터 N-1까지 모두 나누어 보는 것이다. 나누어 떨어지는 수가 존재하지 않으면 N은 소수이다.


1
2
3
4
5
6
7
8
def getPrime(number): #number가 소수이면 출력하는 함수
    if number == 2#2는 소수이므로 바로 출력
        print number,
    for x in range(2,number): #2부터 number-1까지 나누어 본다
        if number % x == 0#나누어 떨어지면 소수가 아니므로 break
            break
        elif x == number - 1#number-1까지 나누어지지 않으면 소수
            print number,
cs

파이썬으로 소수를 구하는 함수를 짜보았다. 가장 이해하기 쉬운 방법이지만, N에 큰수가 들어가면 가장 오래 걸리는 알고리즘이다.


2. N을 2부터 sqrt(N)까지 나누어본다.


위에 방법보다 좀 더 효율적인 방법이다. N=a*b 형태로 나타낼 수 있다. 이 때, a와 b는 둘다 1보다 큰 정수이다. a와 b 둘 중 하나는 sqrt(N)보다 작거나 같다. 그러므로 N을 2부터 sqrt(N)까지 나눠서 나누어지지 않으면 소수이다.


1
2
3
4
5
6
7
8
9
10
11
import math 
 
def getPrime(number): #number가 소수이면 출력하는 함수
    if number == 2#2는 소수이므로 바로 출력
        print number,
    for x in range(2,number): #2부터 number-1까지 나누어 본다
        if number % x == 0#나누어 떨어지면 소수가 아니므로 break
            break
        elif (x > math.sqrt(number)): #sqrt(number)까지 나누어지지 않으면 소수
            print number,
            break
cs

for문으로 N보다 작은 수로 나눌 때, sqrt(N)까지 나눠서 소수여부를 판별하므로 N까지 나누는 첫 번째 방법보다 빠르다.


3. N을 N보다 작은 소수로만 나누어본다.


중학교 때, 소인수분해라는 것을 배웠을 것이다. 이 개념을 이용하는 것이다. 소수가 아닌 수는 N보다 작은 소수로 나누어진다.

12를 예를 들어보자. 12의 약수는 1,2,3,4,6,12이다. 약수 중 소수인 것이 소인수이다. 12의 소인수는 2,3이다. 12는 12의 소인수들의 곱으로 표현할 수 있다. 이렇게 표현하는 것이 소인수분해다. 12는 2^2*3라고 소인수분해 할 수 있다.

즉, 소수가 아닌 수는 N보다 작은 소수로 나누어진다는 것을 알 수 있다. 소인수분해에 대해서 좀 더 알고 싶은 분들은 이 블로그를 참고하면 좋을 것이다.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
import math
 
def getPrime(number):
    primeList = [2#소수 리스트 생성
    num = 3 #3부터 소수인지 검사한다
    
    while (num <= number): 
        for x in primeList:
            if(num % x == 0): #소수로 나누었을 때 나누어지면 소수아님
                break
            elif(x == primeList[-1]): #소수리스트의 끝원소로도 나누어지지 않으면 소수
                primeList.append(num) #구한 소수를 소수리스트에 추가
                break
        num += 1
    
    if(number in primeList): #number가 소수리스트에 존재하면 소수인 것이므로
        print number
cs

마찬가지로 파이썬으로 구현해보았다. 첫 번째 방법보다 적은 수를 나누므로 더 빠르다.


끝으로


위에 3가지 방법을 살펴보았다. 실제로 코딩을 한 뒤, 10만 이상의 큰 수를 넣어보면 실행 차이가 많이 나는 것을 알 수 있을 것이다. 2번과 3번 방법을 혼합하여 더 빠른 알고리즘을 만드는 것도 가능하다.


사실 가장 효율적인 소수 찾는 알고리즘은 에라토스테네스의 체(Sieve of Eratosthenes)방법이 있다. 이 방법에 대해서는 추후에 포스팅할 예정이다.


참고



반응형

'programming' 카테고리의 다른 글

[안드로이드]Android SDK version  (0) 2015.11.05
[안드로이드]프로세스와 스레드  (0) 2015.11.04
소프트웨어 공학이란?  (0) 2015.11.01
Android SDK란?  (0) 2015.10.29
Platform과 Framework의 차이는?  (2) 2015.10.29
반응형

알고리즘 연습하기 정말 좋은 사이트가 있어서 추천드립니다!

dovelet

이 사이트의 장점은

 1. 단계별로 다양한 알고리즘을 재미있게 풀 수 있다.

 2. 랭킹이 있어서 랭킹 올리는 재미가 쏠쏠하다.

 3. 좋은 다른 사람의 알고리즘 풀이를 쉽게 확인할 수 있다. 

입니다.


사이트 주소는

http://www.dovelet.com

입니다!


사이트를 한번 둘러볼까요?

고고

<메인 페이지>

심플한 메인페이지입니다. 아이디와 비밀번호로 로그인도 할 수 있고요. 왼쪽에는 간단한 홈페이지 설명이 나와 있습니다.

<30계단>

30계단 메뉴입니다. 이곳에서는 한계단에 하나의 프로그래밍 문법 문제를 풀 수 있습니다. document도 있는데, 클릭해서 들어가보면, 그 문법에 대한 설명도 자세하게 나와있습니다. 오른쪽엔 사람들이 문제를 제출 했을 때 얼마나 사람들이 통과하는지 비율도 나와있습니다. 비율이 낮을수록 사람들이 어렵게 느껴진 코드라는 것이겠죠?


<document>

위에서 설명드린 document를 들어가면 이렇게 자세하게 문법에 대해서 설명이 되어있습니다. 정말 깔끔하게 잘 설명되어있어서 이해하기 정말 좋습니다!


<문제>

문제를 클릭하면 이렇게 문제를 풀 수 있는 화면이 나오게됩니다. 간단한 문제도 있지만, 위와 같이 재미있는 문제들도 많이 있습니다. 문제를 짜고나서, 하단부분에 채점을 누르게 되면 자신이 짠 코드를 채점 할 수 있습니다. 하단에 이 문제에 대해서 질의응답도 볼 수 있으며, 다른 사람들이 이 문제에대해서 코드를 어떻게 짰는지 확인 할 수도 있습니다.


<옥상>

30계단을 모두 올라가게되면 옥상에 도착하겠죠? 이 곳은 30계단을 올라오면 배웠던 것들을 자유롭게 활용해서 프로그램 문제를 풀어 볼 수 있습니다. 아무래도 옥상이다보니 30계단 문제들 보다는 복잡하고 어려운 문제가 있습니다. 하지만 이 문제들을 모두 잘 풀 수 있다면 우리는 모두 프로그래밍 고수가 될 수 있겠죠?


<랭킹>

이 부분이 이 홈페이지에 상당히 매력적인 부분인 것 같습니다. 이 홈페이지에 모든 사람들이 이렇게 문제를 얼마나 많이 맞추었는지 경쟁을 하게됩니다. 언젠가 높은 랭크에있다면 상당히 뿌듯할 것 같습니다. 하지만 위에 있는 분들은 정말 고수 분들인듯...

 

<개인정보>

개인정보에 들어가면 이렇게 자세하게 자신의 정보를 볼 수 있습니다. 언제 가입을 했는지, 언제 접속을 했는지, 자신의 소속이 어디인지, 그리고 가장 중요한! 자신의 랭킹이 어느정도인지 확인이 가능하죠. 자신이 지금까지 풀었던 문제들도 확인할 수 있어 정말 좋은 것 같습니다.


[추가적으로...]

이 홈페이지는 안타까울지 모르겠지만, 유료입니다. 30계단중에서 3계단까지는 무료로 이용이 가능합니다. 하지만 이런 양질의 문제들과 내용들이라면 돈을 내도 전혀 아깝지 않은 것 같습니다. 아래는 정회원 조건입니다.



단돈 3만원만 입금한다면, 쭉~ 평생 이 모든 프로그램 문제들을 풀고 다른 사람들과 경쟁 할 수 있습니다. 다른 방법으로는 전체랭킹 30위안에 한번만 이라도 들어가게 된다면 쭉 회원을 할 수 있습니다. 하지만 두번째방법은 어려운 방법 같더라구요. 이런 홈페이지를 만든 사람을 위해서 3만원정도는 감사하게 입금 할 수 있다고 생각합니다. 여러분들도 열심히 랭킹올려서 프로그래밍이 같이 프로그래밍의 고수가 됩시다! 

화이팅!!!

반응형

+ Recent posts