라떼는 말이야... 다 C언어 부터 배웠어...

그런데 요즘은 다 python으로 문제풀고 말이야...

Python으로 문제를 풀어?

그렇습니다. 이제는 python으로도 문제를 풀수 있는 시대가 도래했습니다.

C나 C++로 문제를 풀던 많은 사람들이 python으로 문제푸는 것을 두려워합니다.

python의 입출력 방식이 C나 C++과 매우 사맛디 아니하기 때문이죠.

하지만 과연 그럴까요? 익숙해지면 C나 C++보다도 손쉽게 input을 받을 수 있습니다.

머신러닝을 전공하시던 분들은 취직시장에 나와보니 아뿔사 코딩테스트는 봐야하는데, 익숙한 언어가 python 뿐입니다.

알고리즘을 하시는 분들에게 문의를 해보니,

본디 알고리즘은 C++이 짱이다!

python이 세상에서 제일 편한 언어가 되어버렸는데, C++이라뇨...

코딩 테스트 때문에 새로운 언어를 익혀야 하는 불상사를 막고자 이번 글을 작성했습니다.

본 게시글은 맛보기인데, 제가 python으로 문제풀 때 주로 사용하는 테크닉들을 알려드리도록 하겠습니다.

제가 심심할 때 푸는 문제의 솔루션이나, 핫한 코딩테스트 문제들도 여기에 솔루션을 올리도록 할께요.

여러분들의 시간은 소중하니까.

인풋 받기

정수 하나 받기

코드

인풋을 받는 여러가지 방법들이 있습니다. 간단하게 정수 하나를 입력으로 받아 볼까요?

# "10"
N = int(input())
print(N)

이건 솔직히 새로울게 없습니다. input함수를 받고, 그 결과를 int로 캐스팅한 후, 변수 N에 넣어주는 것입니다.

input란?

input()은 입력을 받는 함수라고 알고 있습니다.

그리고 input()의 return형은 항상 str 형입니다.

그렇기 때문에, 들어온 입력을 적절히 가공해 주어야 합니다.

int()

지금으로서는 정수로 변환해주는 캐스팅 같은 역할을 한다고 생각하시면 좋을 것 같습니다.

계속 넘어가도록 하죠. 더 자세히 알 필요가 있다면 더 깊게 설명하도록 하겠습니다.

정수 두개 받기

코드

# 10 20
N, M = map(int, input().split(" "))
print(N+M) # 30

input이 한줄에 2개가 들어온다면 매우 귀찮아 집니다.

2개부터는 각각 인풋을 받아서 나누고 거기에 int로 형까지 변환해줘야합니다.

매우매우 귀찮은 일이 아닐 수 없죠.

위의 코드로 입력을 손쉽게 받을 수 있습니다.

이 코드는 아래 코드와 동일한 방식으로 작동하게 됩니다.

# 10 20
inp = input()
sp_inp = inp.split(" ")
N = int(sp_inp[0])
M = int(sp_inp[1])

int의 정체

N, M = map(int , input().split(" "))

아실지 모르겠지만 python에서 캐스팅하드시 사용하는 int, float와 같은 자료형처럼 보이는 모든 것들이 모두 함수의 형태로 사용합니다.

엄연히 말하자면 class의 형태를 가지고, int로 변환해주는 캐스팅 작업을 해줍니다.

python의 정확한 구조를 모르신다면 함수라고 생각하셔도 무방합니다! 단지 int라는 이름을 가진 함수다 라고 생각하셔도 괜찮습니다.

input 함수가 하는 일

N, M = map(int , input().split(" "))

위에서 설명했듯이 input은 입력을 받는 함수이며, 동시에 str 를 return 합니다.

그리고 더 정확히는 한 라인을 통째로 받는 함수입니다.

이 부분의 기존의 Problem Solving (PS) 계열에 있던 사람들이 고통 받는 이유중 하나입니다.

PS러들은 문자열을 스페이스 단위로 받아서 처리하고 싶어하기 때문이죠...

입력이 뭐가 들어왔던 간에 str로 한 라인을 통째로 받기 때문에 이를 필요에 따라 여러가지 형태로 가공해줘야하는 것이 매우 거슬릴 것입니다.

str의 내장 함수 split

N, M = map(int, input().split(" "))

str에는 다양한 내장 함수들이 있습니다. 이를 통해서 손쉽게 string을 가공할 수 있습니다.

ps러라면 #include <string.h> 나 #include 을 하고 고통받아 보신 분이 있을 겁니다.

python에서는 훨씬 더 쉬운 형태의 인터페이스를 제공 합니다!

pycharm같은 훌륭한 ide를 쓰신다면 "abc". 하고 컨트롤 탭을 하시면 다양한 함수들을 구경하실 수 있을 겁니다.

오늘 알아볼 함수는 split입니다.

이름부터 직관적이게 해당 문자열을 나눠주는 함수입니다.

아래 코드를 확인하시면 어떤 짓을 할 수 있는 녀석인지 직관적으로 깨달으실 수 있을 겁니다.

"10 20 30".split(" ") # ["10", "20", "30"]
"10,20,30".split(",") # ["10", "20", "30"]
"10,20,30,".split(",") # ["10", "20", "30", ""]
"10 20 30 ".split(" ") # ["10", "20", "30", ""]

다만 마지막 두 예제를 조심하세요!

마지막에도 delimiter (구분자?)가 있다면 비어 있는 string을 return할 거에요!

위와 같은 예제를 피하기 위해서는 아래와 같이 strip 함수를 사용해주면 됩니다.

"10 20 30 ".strip().split(" ") # ["10", "20", "30"]

map 함수

이제 마지막으로, map함수를 알아봅시다.

map 함수는 첫번째 인자로 함수를, 두번째 인자로 배열을 받습니다. 그래서 각 배열의 원소에 해당 함수를 적용해주는 함수입니다.

  • (사족1) 사실 함수가 아니라 callable 한 모든 것들이 여기에 올 수 있습니다.
  • (사족2) 사실 배열이 아니라 iterator를 받습니다. 대충 반복할수 있는거라고 생각하시면 될것 같습니다.

말로는 잘 이해가지 않을 것이라고 생각해요. 예제로 이해하는 편이 좋을 겁니다.

arr = ["10", "20", "30"]
map(int, arr) 
# == [int(arr[0]), int(arr[1]), int(arr[2])]
# == [10, 20, 30]

이제 https://www.acmicpc.net/problem/1000 를 풀어볼까요?

마치며

아니 벌써 마치다니요? 사실 맥주 먹으러 가야해서 시간이 없네요.

다 먹고 살자고 하는 건데 맥주한잔하고 오겠습니다.

2탄에서 계속 하도록 할게요!

H. Polynomial BOJ 11500

 

 문제 설명 :

 

  어떤 함수 f(k)를 아래와 같이 정의한다. 

 

 

 이 때 우리는 f에 관한 새로운 식 S(n)을 정의할 건데 그건 또 아래와 같다.

 

이럴 때 S(n)을 n에 관하여 정리해보자면 아래와 같이 정리된다.

 

 

이 때 다음을 구해서 출력하시오.

 

주어지는 것은 다음이다. 

 

 

문제 풀이 :

 

 사실 이런 종류의 수식을 처음 접하는 사람은 이게 대체 뭔 개소린가 싶은 느낌이 들 것이다. 정수론과 굉장히 밀접한 식인데 처음 읽었을 때 도무지 분석을 할 수가 없었다.

 

 S(n)을 f(k)로 풀어보자면 다음과 같다.

일단, 

이식을 보면 이걸 n에 관하여 정리해야 하는데, 정수론에 대해 기초 지식이 있는 사람들은 (사실 고딩때도 배운다) 거듭제곱의 합이 n에 관한 식으로 나온다는 사실을 알 수 있다. 

 

 

예를들면,

 

요런 것들? 

 

따라서 거듭제곱이 같은 것끼리 모아보자.

위 식을 정리하면 아래와 같이 깔끔하게 나오게 된다.

 

 

이제 필요한게 0<=t<=25 사이에 있는 모든 거듭제곱의 합의 계수들만 찾으면 답이다.

 

근데이게 쉽지가 않다. 이 걸 찾기 위해서는 가장 마지막에 주어진 식이 필요하다.

 

 

1부터 n까지 k제곱의 합을 앞으로 T(n,k)라 했을 때 다음과같다.

^증명보시려면 클릭하세요.

 

위 식을 정리하고나면 0~k-1의 거듭제곱합을 통해서 k거듭제곱합을 구할 수 있다.

따라서 0,1,2,3,4...25까지 미리 거듭제곱의 합을 구해놓고 처리하면 끝

 

소스코드 보기 <- 클릭

문제집 : https://www.acmicpc.net/category/detail/1413

풀이는 하나하나 업데이트 될 예정입니다.

간략한 문제 분류와 솔루션만 제시 해놓고 풀이가 따로 필요하다고 생각되는 문제들은 추후 링크 하도록 하겠습니다. (요청하시면 그 부분에 관한 풀이도 올려드리겠습니다. ) 


A. Coin Swap  BOJ 11493


 flow문제 중에서도 MCMF문제다.  "동전의 교환 = 코스트" 로 두고 흰색을 모두 흰색으로 옮길때의 최소 코스트로 그래프 설계를 하면 된다.(검은색을 검은색으로 옮기는 코스트로 생각해도 무방) 흰색 정점이 있는 곳을 src와 연결하고 흰색 동전이 있는 곳을 sink로 돌렸을 때 나오는 MCMF결과를 출력하면 된다.


C. Grid BOJ 11495


 flow 문제 중에서도 이분 그래프로 만든 후 최대매칭하는 문제다. 익히 알려진 사실로 최대 매칭은 flow와 동치다.
 각각의 그리드를 순서대로 1, 2, 3,4... 번호를 매긴 후 인접한 것 끼리 연결한다. 이때 짝수는 src에 홀수는 sink에 연결하며 각각의 캐퍼시티는 그 그리드의 값으로 하고 매칭을 찾으면 된다.
 이 때 결과를 찾는 방법은 두가지 있는데 src와 sink에 남아 있는 캐퍼시티를 추적하는 방법과 전체에서 매칭의 수를 빼는 방법이 있다.(1매칭은 1코스트를 감소시켜주므로) 


D. Kernel  BOJ 11496


 기하 문제다.(segment tree로도 풀린다고 한다.) kernel이 존재할 수 있는 구간을 결정하고 그 위치가 주어진 polygon사이에 존재하는 지 결정하는 문제다. 열심히 그려보다보면 어떤 방식으로 kernel이 존재할 수 있는 구간을 결정하는 지 알 수 있다.(솔직히 이런걸 대회중에 발견하기는 어려워 보인다..)


E. Log Jumping BOJ 11497


 그리디 문제다. 통나무들을 길이 순으로 정렬하고 원의 왼쪽 오른쪽 차례대로 배치해 나가면 최적이 된다. 


F. Odd Cycle BOJ 11498


 그래프 문제 중에서도 SCC를 사용하여 시간을 줄이는 문제다. 사실 진짜 별거 없고 coloring하는데 그 coloring을 SCC내에서 하면 되는 문제다. 근데 한가지 조심해야할게 그냥 돌리면 WA가 날 수 있는데 사이클이 여러개 존재할 수 있다. 따라서 coloring을 back edge만 체크하게 해야한다. 이때 잘 처리 해줘야 TLE가 안난다. 


G. Path BOJ 11499


 기하 문제 중에서도 Convex_hull을 사용하는 문제다. 사실 그냥 컨백스 홀 만드는 방식으로 그냥 쭉 훑으면서 만들면서 최대 값을 갱신만 시켜주면된다.


H. Polynomial BOJ 11500 솔루션


 그냥 수식을 정리하는 문제다. 수학적 센스가 필요한 것 같다. (이미 알고 있다면 개꿀이었을 듯...) 수식을 정리해서 그대로 대입하면 된다. (하루종일 정리하면 된다.) 거듭 제곱의 합에 관하여 정리해야 한다.


I. Stock BOJ 11501


 파라매트릭 서치 문제다. 특정 상한을 결정하고 만들 수 있는지 검사한다. 이 때 검사는 선형으로 할 수 있어서 O(n) 그리고 파라매트릭에 logn이 들어 총 O(nlogn)이 든다. 


J. 3-Primes Problem BOJ 11502

 

 추측이라는데 그런가 보다 하면 된다. 그냥 하라는데로 하면 되는데 1000밖에 안된다. 따라서 소수 a,b를 결정하면 자동으로c가 결정된다. 여러가지 방법이 있는데, 전수 검사를 해서 (a,b,결정하고 c가 소수인지 확인) 푸는 방법, 넵섹하는 법, 등등 있다.


K. Tree Edit BOJ 11503


트리 dp문제다. 아직 안풀었다.


 L. Wheel of Numbers BOJ 11504


시뮬레이션 문제다. 직접 다해보면 된다. 




+ Recent posts