* 제 개인적인 생각으로 적는 포스트라 틀린 내용이 있을 수도 있습니다.

* 댓글에 적어주시면 감사하겠습니다.

 

IDE를 고르자

개발 환경을 세팅하는 것은 개발 속도에 아주 많은 영향을 미치기 때문에 개발 환경을 잘 세팅하는 것이 정말 중요하다.

이를 위해서 많은 IDE(통합 개발 환경 프로그램)들이 존재하는데... 자바 언어의 경우에는 이클립스나 인텔리제이가 많이 쓰이고... 파이썬은 vscode, 주피터, 파이참 등을 많이 쓰는 것 같다.

그러면 C++에서는 어떤 IDE를 쓰는 게 좋을까?

C++ IDE에는 visual studio도 있고, CLion도 있다.

또 IDE라고 보기는 좀 애매하지만 VS code도 있다.

 

뭘 사용해야 할까?

모두 굉장히 좋은 IDE들이지만... Effective C++ 의 저자인 스콧 마이어스는 적어도 코딩을 시작할 때만큼은 IDE를 사용하지 않기를 권장한다.

나도 같은 생각이고, 나는 실제로 일을 할 때도 IDE를 따로 쓰지 않고 vim이라는 에디터를 사용해서 코딩한다.

vim에 대한 아주 간단 설명

vim에 대해 간단하게만 설명하자면... vim은 linux 계열 환경에서 많이 사용하는 에디터인데, IDE에 비해 아주 가벼운 에디터다.

(linux에 대해 잘 모른다면 windows와 같은 os 중에 하나라고 생각하면 된다. 서버 장비로 굉장히 많이 쓰이는 os다.)

vim은 windows의 메모장과 비슷하다면 비슷하지만, 메모장에 비하면 훨씬 많은 기능을 가지고 있고 원한다면 plugin을 깔아서 IDE처럼 사용할 수도 있다.(원하는 기능만 깔기 때문에 엥간히 많이 깔아도 IDE보다는 훨씬 가볍다)

vim을 사용하는 데 익숙해지면 코딩할 때 굉장한 손맛을 느낄 수 있으므로... 개인적으로는 vim을 사용하길 추천하지만, emacs(vim과 경쟁? 관계인 editor)나 다른 IDE를 사용해도 상관은 없다.

중요한 건 자신한테 맞는 개발환경을 세팅하는 것이니까...

 

참고로 windows에서 vim을 사용하려면 wsl에서 사용하는 것을 추천한다.

wsl에 관련해서는 조금만 검색해봐도 대량의 데이터가 나오니까 잘 찾을 수 있을 거라고 생각한다.

mac os에서는 그냥 vi 사용하면 된다.

 

그럼 vim 사용법에 대해서는 나중에 다른 포스트에서 설명하기로 하고.. 다음으로 넘어가자

 

어떤 운영체제(Operating System)에서 개발할까?

자, vim이든 IDE든 골랐다고 개발환경 세팅이 끝난 게 아니다.

어떤 운영체제(os)에서 개발할 것인지도 정해야 한다.

당연히 windows 아냐? 하는 사람들도 있을 수 있지만, 나는 좀 다른 추천을 하려고 한다.

나는 ubuntu 22.04 에서 실습을 할 것이다.

"ubuntu가 뭐야?" 한다면 앞서 말했던 linux os의 여러 버전 중에 하나라고 생각하면 된다.

왜 ubuntu에서 실습하려고 하냐면... 예전에 클라우드 서버를 하나 받아놓은 게 있는데 이게 아까워서... 는 농담이고,

아주 많은 서버들이 linux 계열로 되어 있기 때문에 개발을 windows에서 하더라도 실제로 그 프로세스가 돌아가는 것은 linux os에 해야하는 경우가 많다.

나는 개발환경과 실제로 프로세스가 운영되는 환경을 일치시키는 것이 좋다고 생각해서, 그냥 리눅스에서 개발하는 것을 좋아한다.(vim 쓰기도 편하고 ㅎㅎ)

* 배포 : "내가 개발한 프로그램을 실제 서버에서 실행시키는 일" 정도로 생각하면 된다.

* linux에 대해서는 따로 좀 더 정리해보겠다.

 

근데 그러려면 "ubuntu os 컴퓨터를 사야하는 거 아냐? 그렇게까지 해야돼?" 할 수 있는데 그렇지 않다.

다양한 회사에서 ubuntu os 장비를 대여해주고 있다.(나는 cafe24에서 월 3만원 주고 쓰고 있다.)

그냥 내 컴퓨터에서 대여한 장비에 원격으로 접속해서 개발하면 된다.

IDE를 사용해도 당연히 원격 개발 서버에 접속해서 하는 기능이 있으니까 걱정하지 않아도 된다.

(그 유명한 AWS에서는 free tier(공짜)로도 서버를 제공하긴 하는데 사용해보니 너무 스펙이 딸려서 그냥 안 쓰는 게 낫겠더라..)

 

"아 난 싫어, 돈 아까움" 하면 그냥 자기 컴퓨터에 깔려있는 os에서 해도 된다.(아마 대부분이 이렇지 않을까 싶다)

다만 mac os는 상관없지만 windows에서 할 거면 wsl에서 하는 걸 조금 더 추천하긴 하는 정도다.

(wsl 사용은 간단하니 검색해서 해보길 바란다.)

왜이렇게 windows를 싫어하냐고?

안 싫어한다.

그냥 나랑 다른 os를 사용하다가 "너는 되는데 나는 외않되?" 하는 상황이 발생할까봐... 개발환경을 나와 맞춰주길 바라는 마음이다.

 

C++ version 고르기

C++이라고 다 같은 C++이 아니다.

세상이 발전하면서  C++도 발전한다.

C++이 발전하면서 뒤에 붙는 버전이 높아지는데, C++11 C++14 C++17 C++20 등이 있다.

나는 C++17이 익숙해서 C++17 쓸 것이다.

뭘 써도 상관 없지만 가능하면 C++14 이상을 사용하길 권장한다.

(중요한 문제는 아니라서 웬만하면 나랑 똑같이 C++17 쓰는 게 좋을 것 같다.)

 

컴파일러 설치

#include <iostream>

int32_t main(void)
{
    std::cout << "Hello World!\n";
}

내가 위의 코드를 짰다고 해보자!(당연히 뭔 내용인지는 몰라도 된다)

근데 이 코드는 인간만이 이해할 수 있다.

컴퓨터는 0과 1만 인식하기 때문에 저것만 보고는 뭘 어떻게 해야할지 알 수 없다.

그러면 뭐가 필요할까?

내가 짠 코드를 컴퓨터가 이해할 수 있도록 바꿔주는 과정이 필요하다!

그걸 해주는 게 컴파일러다.

C++ 컴파일에는 g++이 많이 사용되므로 g++을 사용하도록 한다.

근데 이 g++에도 version이 있다.

g++ version에 따라 컴파일할 수 있는 C++ version이 다르다.

내 환경인 ubuntu 22.04에서는 default g++ version이 11이고, C++17을 지원하므로 굳이 따로 설치할 필요는 없겠다.

 

"내 g++ version은 어떻게 알고 설치는 어떻게 하냐!" 한다면...

$ g++ --version

커맨드 창에 저렇게 입력해보길 바란다. (앞의 '$'는 빼고 입력해야 된다. shell prompt라는 걸 말하기 위해표시해둔 것이다.)

그러면 아래처럼 g++ version이 나올 것이다.

 

version이 너무 낮다? 하면 g++ 11을 설치해주도록 하자.

아래 커맨드를 입력하면 된다.(wsl shell 창에서 입력해야 될듯)

windows는 내가 직접 해본 게 아니라 이거 안 되면 직접 찾아서 해야한다ㅠ

$ sudo apt-get install gcc-11

 

 

M1맥북 gcc11 설치하기, VScode 연동

맥북에 GCC를 깔아보자

joong-sunny.github.io

mac os는 default compiler가 clang으로 되어 있기 때문에 이 링크를 참조해서 설치하면 될 것 같다.(아마 설치 안 해도 실습 코드 돌리는 데는 문제 없을 것 같다.)

 

테스트해보자

아마 내가 세팅 과정을 너무 대충 써놔서 다른 블로그의 포스팅들을 많이 참고해야 하지 않을까 싶긴 하지만...

일단 다 됐다!

잘 됐는지 테스트해보고 마무리하자.

 

"main.cpp" 라는 파일을 만들고 파일에 아래처럼 입력해보자.

#include <iostream>

int32_t main(void)
{
    std::cout << "Hello World!\n";
}

그리고 g++을 이용해서 커맨드창에 아래처럼 입력해본다.(앞서 말했듯 $는 빼고 입력해야 한다.)

컴퓨터가 이해할 수 있는 코드로 컴파일이 될 것이다.

$ g++ main.cpp -std=c++17

"g++"이 "g++ 을 수행시켜라!" 라는 의미고

"main.cpp"가 앞서 작성했던 "main.cpp 코드를 컴파일해라!"라는 의미다.

"-std=c++17"은 당연히 "c++17 version을 사용해라!"라는 의미다.

 

아무것도 출력되지 않고 끝난다면 컴파일이 잘 된 것이다.

그다음에 만들어진 실행파일을 실행시켜보자.

$ ./a.out

이렇게 입력하면 아래처럼 "Hello World!"가 출력될 것이다.

그러면 성공!

'프로그래밍 언어 > C++' 카테고리의 다른 글

코드가 돌아가는 원리  (1) 2023.12.28
프로그래밍과 C++  (0) 2023.12.27
[C++] accumulate 함수  (1) 2020.12.29

* 제 개인적인 생각으로 적는 포스트라 틀린 내용이 있을 수도 있습니다.

* 댓글에 적어주시면 감사하겠습니다.

 

프로그래밍은 프로그래밍 언어를 사용해 원하는 기능을 만들어내는 것이라고 했었다.

이 과정에는 내가 만들 프로그램의 설계, 구현, 테스트 등 여러가지 단계가 포함된다.

여러 단계를 거치며 프로그래밍을 하는 과정에서 코드를 작성하는 작업을 "코딩을 한다"라고 한다.

그러면 내가 코딩한 코드는 어떻게 돌아갈까?

 

프로세스가 돌아가는 원리

 * 참고)

    - 프로그램 vs 프로세스

    - 프로그램은 개발자가 만들어낸 작업물을 말하고 이 프로그램이 실행 중일 때 이 실행 중인 프로그램을 프로세스라고 한다.

 

 내가 작성한 프로그램이 돌아가는 원리를 알려면 프로세스가 컴퓨터의 어떤 부위(?)를 사용하는지 알아야 한다.

간단하게 컴퓨터가 cpu, 메모리, 디스크로 구성되어 있다고 보자.

내가 작성한 코드에는 수행해야 하는 명령이 있고, 명령을 수행하기 위해 필요한 자원이 있어야 한다.

이 자원은 잠시 동안만 사용하고 버릴 수도 있고, 반영구적으로 저장해야 할 수도 있다.

명령을 수행하는 주체가 cpu, 잠시 사용하고 버릴 자원을 저장하는 곳이 메모리, 반영구적으로 저장할 곳이 디스크다.

 

 

한번 비유적으로 이해해보자.

회사에서 상사가 부하직원에게 매월 주기적으로 포켓몬 빵을 주문하는 일을 시키려고 한다.

"포켓몬 빵을 주문해라!" 이 부분이 명령에 해당한다.

좀 더 명령을 세분화해보자.

 

포켓몬 빵을 주문하기 위해 상사는 부하직원에게 아래 4가지 명령을 수행시킨다.

  step 1. 전국의 포켓몬 빵 공장의 전화번호를 파악해라.

  step 2. 각 공장에 연락을 돌려 가격을 파악해라.

  step 3. 가장 싸게 파는 공장을 기록해둬라.

  step 4. 매월 주기적으로 포켓몬 빵을 주문해라.

부하직원은(cpu) 위 4가지 명령을 수행해서 포켓몬 빵을 주문할 것이다.

 

# step 1

부하직원(cpu)은 1번 명령을 수행하면서 포켓몬 빵 공장의 전화번호를  알아내긴 하는데...

어떻게 공장 전화번호를 다 기억할까...?

그래..! 부하직원(cpu)는 공장 전화번호를 종이(메모리)에 적어두기로 한다.

 

# step 2

그 다음 종이(메모리)에 적힌 전화번호(자원)를 보고 공장에 전화를 돌려 포켓몬 빵 가격을 파악한다.(2번 단계)

 

# step 3

또 빵 가격을 종이(메모리)에 적어뒀다가 종이(메모리)를 보고 가장 싼 공장을 찾는다.

근데 이 종이는 곧 버려질 운명이다. 아무리 종이를 잘 숨겨도 오늘 퇴근하고나면 사무실을 청소 직원분이 가차없이 버릴 것이다.

흠... 이건 나중에 또 써야하는 정보라 잘 보관해둬야 하는데...

그래, 좀 멀더라도 저기 창고에 있는 금고(디스크)에 넣어두자.. 

 

# step 4

그 다음 포켓몬 빵을 주문할 때마다 부하직원(cpu)은 창고에 가서 금고(디스크)를 열고 종이(메모리)에 공장 전화번호를 적어온 다음 포켓몬 빵을 주문한다. (4번 단계)

 

사실 위 내용은 프로세스가 돌아가는 과정을 굉장히 축약해서 이야기한 거긴 하다.

어떻게 보면 복잡하고, 어떻게 보면 단순하지만 이해가 되면 좋겠다.

 

결론적으로 코딩을 한다는 것은...

프로그래밍 언어를 사용해서 컴퓨터가 수행시킬 명령과 명령을 수행하기 위해 필요한 자원을 어디에 어떻게 저장할지 등을 컴퓨터에게 알려주는 일인 것이다.

'프로그래밍 언어 > C++' 카테고리의 다른 글

개발환경 세팅  (1) 2024.01.14
프로그래밍과 C++  (0) 2023.12.27
[C++] accumulate 함수  (1) 2020.12.29

* 제 개인적인 생각으로 적는 포스트라 틀린 내용이 있을 수도 있습니다.

* 댓글에 적어주시면 감사하겠습니다.

프로그래밍과 프로그래밍 언어

몇년 전부터 개발자 품귀 현상과 고급 개발자 수요 증가에 힘입어 개발자 취업 열풍이 불고 있다.
신입 연봉 5천만 원, 6천만 원을 내걸면서 대학 서열마냥 네카라쿠배당토하야직샌... 줄줄 귀족 IT 서비스 회사들이 입에 오르내리곤 한다.
그러면 개발자는 무슨 일을 하는 사람일까?
주변에 이런 질문을 하면 많은 사람들이 "개발자? 프로그램 만드는 사람 아냐?"라고 대답하곤 한다.
맞다. 조금만 더 구체적으로 말하자면 "개발자(프로그래머)는 개발자는 프로그래밍 언어를 사용해서 원하는 기능을 만들어내는 사람"을 말한다.(적어도 내 생각에는...)
그래서 개발자가 되기 위해 많은 사람들이 프로그래밍 언어를 공부한다.

그러면 프로그래밍 언어는 뭘까?
개인적으로는 프로그래밍 언어란 개발자가 원하는 기능을 만들기 위해 컴퓨터와 사람이 소통하는 언어라고 생각한다.
많이 알려져있듯, 컴퓨터는 0과 1만으로 대화를 한다.
하지만 사람은 그렇게 대화할 수 없다. 상대방에게 "밥 먹었어?" 물어보려고 "010111101000011011010101..." 이렇게 질문해야 한다면, 아마 인류는 복장이 터져서 평균 수명이 10년도 안될 것이다.
그렇다고 컴퓨터한테 "밥 먹었어?"라고 하면 컴퓨터가 이해할 수 있나? 당연히 안 된다.
그래서 사람과 컴퓨터가 소통하기 위해서는 그 중간 수준의 언어로 대화해야 한다.
그것이 프로그래밍 언어다.

C++이란?

앞서 말한 프로그래밍 언어에는 자바, 파이썬 등 많은 언어가 있는데, 그중 가장 전통(?) 있는 언어 중 하나가 바로 C++이다.
이 C++ 언어는 C언어에 기반한 언어로 C언어에 객체지향 개념을 탑재했다고 보면 된다.(객체지향 개념은 나중에 얘기를 해본다)
나도 대학교 수업 때 첫 학기에는 C언어를 배우고 두 번째 학기에는 C++을 배웠다.
그 후로는 C++을 사용해 자료구조를 구현하고, 또 그 자료구조를 이용해 이것저것 재밌는 걸 만들어보는 수업을 들었었다.
그리고 우리 학교뿐만 아니라 많은 학교의 컴퓨터공학과에서 이처럼 C언어와 C++을 기본으로 배우도록 커리큘럼이 짜여져 있을 것이다.

많은 곳에서 왜이렇게 C언어와 C++을 기본으로 배우도록 했을까?
내 생각에는 크게 두 가지 이유가 있다.

1. C++은 컴퓨터를 이해하기 좋은 언어다.

사람의 언어에 가까울수록 추상화 정도가 높다고 하고, 컴퓨터에 가까울수록 추상화 정도가 낮다고 한다.
추상화 정도가 낮을수록 컴퓨터를 이해하기 좋다.
내가 만든 코드가 어떻게 메모리를 사용하는지 등 컴퓨터가 어떻게 동작하는지 이해할 수 있다.
C/C++은 대표적인 추상화 정도가 낮은 언어기 때문에 컴퓨터를 이해하기 위해 C/C++로 프로그래밍 공부를 시작하는 경우가 많다.

2. 빠르다.

추상화 정도가 높은 많은 언어들(파이썬과 같은)은 높은 추상화 수준을 유지하기 위해 어느정도 속도를 trade-off 한다.
그래서 예로부터 속도가 중요한 프로그램(게임 엔진 같은)은 C/C++로 구현하는 경우가 많았다.
(하지만 요즘은 다른 언어도 그렇게 느리지 않기 때문에... 정말 정말 속도가 중요한 경우가 아니면 굳이 C++로 할 필요는 없지 않을까 싶다.)

 

 

뭐 이런 장점들이 있긴 하지만 C++은 다른 언어에 비해 상당히 어려운 언어다.
또 C++은 개발자 역량에 따라 오히려 더 속도가 느려질 수도 있고, 유지보수에도 더 많은 비용이 들 수 있다.
하지만 그럼에도... 프로그래밍을 제대로 공부하고자 한다면 C/C++부터 시작해보는 건 꽤 괜찮은 선택이 아닐까 싶다.

'프로그래밍 언어 > C++' 카테고리의 다른 글

개발환경 세팅  (1) 2024.01.14
코드가 돌아가는 원리  (1) 2023.12.28
[C++] accumulate 함수  (1) 2020.12.29

https://search.shopping.naver.com/book/catalog/32550285396?cat_id=50005622&frm=PBOKPRO&query=%EC%97%AD%ED%96%89%EC%9E%90&NaPm=ct%3Dlm1gx5c0%7Cci%3D1ba16de0eb696258e40bda696b8a0fb4c4341107%7Ctr%3Dboknx%7Csn%3D95694%7Chk%3D48bf6a17e5e51c662dba5cfdd3dad5d6ef6accc6 

 

역행자 : 네이버 도서

네이버 도서 상세정보를 제공합니다.

search.shopping.naver.com

이 책은 성공한 젊은 사업가인 자청 님이 자신의 이야기를 바탕으로 경제적 자유로 나아가는 삶의 원칙을 소개한 책이다.

왜 이 책을 읽게 되었나

근 10년 간 1년 평균 독서량 0권에 수렴하는 삐리리뽀옹은 역설적이게도 서점에 가는 것을 굉장히 좋아한다.

서점에서 경제, 자기계발, 개발 관련 서적들을 보면 그 책을 읽고 지식과 통찰력을 키워갈 생각에 설레는 느낌이 좋았다.

그 설렘을 실현하고자 종종 책을 사긴 하지만 사실상 책장을 펴지도 않는 경우가 많았고(전공 서적 제외)... 그렇게 약 10년 정도가 흘러버렸다...

 

그러던 와중 친구 한 명이 역행자를 인생 책이라고 소개해줘서.. 인생을 다시 한번 리프레쉬해볼까 하는 생각으로 책을 구매하게 됐다.

즉, 현실에 쫓기는 아둥바둥, 무계획, 무지향적인 삶에서 벗어나고자 이 책을 읽게 되었다!

(하지만 isfp라 어쩔 수 없이 구매 후 반 년 정도 지난 지금에서야 책을 읽었다.)

 

"역행자"와 "순리자"

사람은 세상이 시키는 대로... 유전자가 시키는 대로.. 자연스레 사는 사람과 세상과 유전자를 역행하는 방식으로 사는 사람으로 나뉜다.

전자는 "순리자"고, 후자는 "역행자"다.(물론 이분법적으로 두 유형의 사람만 존재한다고 볼 수는 없다)

순리자로 산다면 당장 몸과 머리는 편할 수 있지만 적어도 경제적 관점으로는 중장기적으로 남들보다 나은 삶을 살기 어려울 가능성이 높다.

그러므로 진정한 경제적 자유를 원한다면 역행자로서의 삶을 살아야 한다.

(개인적으로는 경제적 자유뿐 아니라 인생의 거의 모든 일에 통용되는 말인 것 같다.)

 

역행자가 되는 7단계

저자는 역행자자로 살며 경제적 자유를 이루기 위한 7단계를 소개한다.

 

1단계 - 자의식 해체

역행자가 되기 위해 가장 중요한 단계가 자의식 해체다.

책에서 말하는 "자의식"은 타인의 조언을 받아들이지 않으려는 마음을 의미하며, "자의식"의 사전적 정의와는 약간 포인트가 다른 것 같다.

내 주변에도 아래와 같은 여러가지 이유로 자기계발 서적을 싫어하는 사람들이 있다.

 

- 그 사람이 그렇게 대단해? 그 책 볼 바에 다른 더 성공한 사람의 책을 볼래.

- 그 사람은 나와 살아온 환경이 아예 다르잖아. 그걸 인생의 진리인 양 말하는 게 싫어.

- 당연한 소리를 고상한 척 써놨네..

- 아 시부럴 몰라 열심히 싫어 나 안 해!

- 어차피 난 저렇게 해도 안 돼...

- 등등..

 

이런 게 책에서 말하는 자의식이고, 이런 태도를 고수한다면 설령 인생을 바꿀 수 있는 조언이라도 받아들이기 힘들다.

그래서 먼저 다른 사람의 경험과 의견을 무조건적으로 거부하지 않도록 자의식을 해체해야 한다.

선입견 없이 타인의 의견을 듣고, 객관적으로 수용할 만한지 아닌지 판단하도록 하자.

아집에 갇히면 열심히 살더라도 성장의 방향과 속력을 장담할 수 없다.

 

2단계 - 정체성 만들기

내가 원하는 미래를 위해 내가 지금 갖춰야할 정체성을 만들어야 한다.

예를 들어 훌륭한 개발자가 되고 싶다면...

훌륭한 개발자들의 책을 읽거나, 훌륭한 개발자가 되려는 모임에 나가거나 할 수 있다.

혹은 주변에 난 진짜 훌륭한 개발자가 될 거야라고 말하고 다닌다거나 6개월 안에 깃헙 스타 500개 받기 같은 자신만의 벌칙을 정해도 된다.

자신의 정체성을 만들어 놓으면 의식적으로 무의식적으로 그렇게 되기 위해 노력할 가능성이 높다.

실제로 나도 굉장히 개발도 잘하고 일도 잘하는 회사 선배님을 보면서, 어떤 문제에 닥쳤을 때 "내가 그 선배님이었다면?" 하고 생각하면서 문제 해결을 시도했던 적이 꽤 있다. 돌이켜보면 이런 게 정체성 만들기 아니었을까 싶다.

3단계 - 유전자 오작동 극복

아주 오랜동안 자연의 섭리에 따라 인간의 유전자는 생존과 본능에 맞춰 진화해왔다.

인간의 유전자는 "배고프면 먹어라", "졸리면 자라", "하기 싫으면 하지 마라" 등 원초적 본능에 맞춰 뇌에게 행동을 지시한다.

유전자의 이런 지시는 수렵생활 하던 때에는 생존을 위한 효율적 동작이었을지는 몰라도, 현대에서의 사회적 생존을 위해서는 적합하지 않다.

물론 1차원적 생물학적인 욕구는 어느정도 필요하긴 하지만, "하기 싫으면 하지 마라"와 같은 건강에 지장을 주지 않으면서 성장을 억제하는 명령은 사람을 순순히 유전자 명령에 따르는 순리자에 머무르게 한다.

무언가 하기 싫다면..? 무언가 시작하기 두렵다면..? 그 마음이 유전자 오작동에서 기인한 것인지 생각해보자.

나도 일할 때 일의 우선순위를 잘못 정하는 경우가 많다.

"이건 나중에 해도 돼" 생각하지만, 다시 돌이켜보면 몇몇 경우에는 내 판단의 실질적인 근거가 "급한 or 중요한 일이 아니라서"가 아니라 "이 일에 대해 모르는 게 너무 많아. 무서워"였던 것 같다.

사실 나는 이런 판단을 할 때 마음 한켠에 아주 작게라도 떳떳하지 못한 찝찝함이 남아있다.

이런 찝찝함을 잘 캐치해서 내가 한 판단이 유전자 오작동에서 기인한 것일까 생각해야 한다.

4단계 - 뇌 자동화

대개 인간의 뇌는 성인 이후로 기능이 퇴화한다고 생각한다.

나 또한 그랬다.

하지만 인간의 뇌는 성인이 되어서도 성장할 수 있고, 그럴수록 복리의 마법이 펼쳐진다.

뇌를 자동화시키는 방법은 간단하다.

책 읽고, 글쓰고, 잘 자고, 안 해본 일을 해라

사실 책의 서두부터 책이 끝날 때까지 저자가 계속 강조하는 게 독서와 글쓰기다.(2년 동안 하루 2시간씩 독서&글쓰기하라며 22 전략을 강조함)

유전자 오작동일지는 몰라도 나는 하루 2시간씩 독서와 글쓰기에 할애하는 건 솔직히 자신 없다.

그러면 하루에 1시간이라도, 30분만이라도 해보자. 그것도 안 되면 주말만이라도 해보자.(책에서도 이렇게 하라고 한다)

안 해본 일을 하며 뇌를 골고루 발달시키는 것도 중요하다.

안 가본 길을 가보고, 안 해본 운동을 해보고, 안 해본 게임이라도 해보자.

5단계 - 역행자의 지식

5-1. giver가 돼라

애덤 그린트의 "기브 앤 테이크"라는 책에서는 인간 관계에서 사람을 giver, taker, matcher 이 세 부류로 나눈다.

이 유형 중 성공한 사람은 giver가 가장 많다.

역설적이게도 가난한 사람도 giver가 가장 많다.

성공한 giver와 가난한 giver의 차이는 누구에게 선의를 베푸냐의 차이다.

giver에게 베푸는 선의는 언젠가 직간접적으로 반드시 돌아온다.

이것저것 따지지 않고 1을 받으면 2를 돌려주자.

하지만 taker나 matcher에게 아가페적인 선의를 베푸는 건 주의해야 한다.

가장 가난한 사람도 giver다.

 

5-2. 객관적으로 판단하라

감정적으로 판단하지 말고 확률에 기반해 배팅해라.

당연한 말이다. 경제학에서도 "차가운 머리 뜨거운 가슴"이라는 유명한 알프레드 마샬의 명언이 있다.

 

5-3. 타이탄의 도구를 갖춰라

인생의 기회를 만들어줄 수 있는 혹은 기회를 잡을 수 있는 타이탄의 도구를 갖춰라.

책의 예시로는 블로그 마케팅 기술, 유튜브 편집 기술 등이 있다. 작게는 운전면허같은 것도 있을 것이다.

이 타이탄의 도구들이 모여 굉장한 시너지를 낼 수 있다.

 

6단계 - 경제적 자유를 얻는 구체적 루트

5단계까지 한다면 6단계부터는 알아서 따라올 것 같다.

잘하고 싶은 분야(개발이든 투자든)를 파고들며 공부해라.

책을 20권 이상 읽고, 관련 유튜브를 보고, 온/오프라인 강의를 들어라.

또 배우고 느낀 걸 글로 써라.

7단계 - 역행자의 쳇바퀴

앞의 단계를 반복하면 된다.

그러면 역행자가 될 것이다.

 

읽고 나서...

여러 부분에서 뼈를 맞아 순살 삐리리뽀옹이 되었지만..

특히 강하게 맞은 부분은 기억력에 대한 내 태도였다.

나는 내 기억력이 안 좋다는 것을 알고 있었다.

시간이 갈수록 더 안 좋아진다는 것도 절실히 느끼고 있었다.

하지만 난 이 현상이 노화에 따른 자연스러운 현상이라고 생각하고 그냥 받아들였었다.

순리자다운 행동이었다.

기억력이 안 좋아지면.. 내 어떤 행동이 기억력을 악화시키는지.. 기억력을 개선하기 위한 방법이 있는지..

나를 탐구하고 책을 읽으며 방법을 찾아보고 노력했어야 했다...

 

책에서 하는 말과 달리 개인적으로 인생은 절대 쉽지 않다.

역행자가 되면 쉽지 않은 거겠지, 역행자가 되고자 노력하는 것 자체가 어렵다.

하지만 그렇다고 빈둥대는 삶이나 현실에 쫓기기만 하는 삶, 즉 자유가 없는 삶을 살고 싶지는 않다.

자유를 위해 책에서 계속 강조하는 독서와 글쓰기를 블로그를 통해 시작해보려 한다.

isfp의 성향을 버리고, 이번만큼은 꾸준히!

 

참고로 본 포스팅은 책의 내용을 아주 많이 간추린 것이기 때문에...

좀 더 자세히 알고 싶거나, 사례를 접하고 싶으면 반드시 책을 직접 읽어보길 바란다.

역행자로 살 수 있도록 훨씬 더 큰 동기를 부여해줄 것이다.

정말 오랜만에 글을 올리는 것 같다.

참고로 유안타 증권 면접은 삐리리뽀옹이 20년도 상반기에 봤던 면접이다.

 

----------------------------------------------------------

 

유안타 증권 자소서를 쓸 당시의 삐리리뽀옹은 ibk 듀오에게 두들겨맞은 상태라 자괴감이 상당했다.

(왜 그랬는지는 앞의 글들을 보면 아실 수 있다.)

 

금융 ptsd로 인해 "다시는 금융권에 발도 들이지 않겠노라..." 다짐했던 삐리리뽀옹...

농담이고 붙여만주면 전재산이 들어있던 삼성증권 계좌를 그대로 폐기할 수도 있다는 마음으로 유안타증권에 자소서를 쓰기 시작했다.

 

하... 양은냄비의 전사 삐리리뽀옹.. 얼마 쓰지도 못하고 카페에서 지쳐갔던 게 아직도 기억난다..

왜이렇게 금융권 자소서는 힘들까...

(사실 개발 경험과 비개발(금융) 경험이 둘 다 꽤 있었는데, 뭘 더 어필해야하는지도 잘 몰랐고 찾아보지도 않았다...)

하지만 삐리리뽀옹이 누구인가?

어떻게든 되겠지! 마인드 하나로 살아온 isfp 의 삐리리뽀옹 아니었던가!

"그래.. 넌 내가 지킨다..." 소중한 삼성증권 계좌에게 한마디 건네고 어김없이 대충 자소서를 제출한다.

 

결과는 자소서 합격!

아마 경제학전공자라 붙을 수 있었던 것 같다.

 

또 얼기설기 1차 면접을 보게 된 삐리리뽀옹...

지난 패배들의 아픔을 되새기고 예상 질문까지 작성하며 이번만큼은 진짜 열심히 준비한다.

 

1차 면접은 실무 면접으로 화상면접이었다.

훗.. 난 이미 11번가에서 화상 면접을 경험해봤다굿..! 그때 깨진 뚝배기를 기필코 이어붙이리라...!

예상 질문 리스트를 검토하고... 미리미리 새하얀 샤쓰도 입어두고... 머리카락도 한올한올 오와열을 맞춰본다.

열정을 너무 빨리 썼나.. 면접까지 시간이 좀 남았지만 집중력이 흐트러져버린 삐리리뽀옹은 해서는 안 될 짓을 하고야 만다.

 

정신차리기 위해 샤쓰를 벗어던지고 팔굽혀펴기를 해버린 삐리리뽀옹...

대충 정신만 차리고 그만뒀어야하는데 땀이 나고 얼굴이 시뻘개질 정도가 됐다.

사실 여기까지만 해도 괜찮았다...

면접까지는 10분 정도 남았기 때문에, 호흡 가다듬고 다시 용모단정하게 세팅하면 된다..!

 

하지만 운동이 끝나자마자 울리는 카카오 페이스톡!

뭐지 엄만가? 하고 "아들 면접 봐야되니까 끊어!" 라며 역정을 내려던 순간...

모르는 이름이다...! 면접인가...!

아니 10분이나 남았는데 왜 벌써...!

 

하지만 이미 닥쳐버린 일... 벨소리는 계속 울리고 삐리리뽀옹은 부리나케 샤쓰를 입는다.

모든 뽀옹의 세포들은... 내 거친 호흡과... 불안한 땀방울과... 허둥대며 단추를 헛잠그는 손가락 탓에 보라색 고구마가 돼버린 지 오래였다.

마지막 단추를 잠그며 허겁지겁 페이스톡을 받은 삐리리뽀옹.

휴대폰 화면에 보이는 세 명의 면접관을 보고 "아 시X..." 탄식했다.

 

하지만 30분 동안 진행됐던 면접은 다행히도 초반에만 좀 긴장하고 나머지는 잘 대답할 수 있었다.

지금 생각하면 그럴 수 있던 이유는 (화상 면접이었기에 가능한) only 빤스 하체로 내 뜨거운 열정...! 아니 열기를 일부 식힐 수 있었다는 것이었다.

 

농담이고 그냥 달달 외워둔 1분 자기소개를 하면서 호흡 정리하고, 고민하는 척 얼굴에 손 대서 땀 닦고 했던 게 컸던 것 같다.

질문 자체도 그렇게 어렵지 않아 다행이었다. (지금 생각하면 나에게만 그랬던 걸 수도 있지만 대부분 금융권 it 면접의 질문들은 그렇게 어렵지는 않았던 것 같다. 적어도 개발 지식적으로는... 나중에 기회가 되면 금융권과 it 서비스 면접 비교 글을 써볼 수도 있겠다)

 

삐리리뽀옹은 그렇게 1차 면접도 여차저차 합격하게 되고 마지막 2차 면접을 보게 된다.

2차 면접은 전화 면접이었다.

매일 다짐하지만 어렵게 얻은 기회를 놓치지 말자.. 이번엔 진짜 깔끔하게 준비했고 면접 직전 헛짓거리도 안 했다.

너무 완벽하게 준비했던 탓일까... 이럴 때 인생 최고의 밍밍한 면접을 보게 된다.

결혼 승낙 받으러 여자친구 집에 인사를 가면 이런 느낌일까...

"넵 형제는 없구요, 저희 아버지는 뭘 하시구 어머니는 뭘 하십니다. 본가는 어디구요, 호롤롤로!"

15분 동안 저런 소리만 하고 끝났다.

마지막에 "딸내미를 제게 주십쇼 장인어른" 할 뻔했다.

농담이고 그렇게 2차 면접도 붙게 됐다.

 

잉? 근데 갑자기 최종 면접이 한 번 더 남았다더라.

근데 형식상 면접이지 대표님이었나? 여튼 높은 분이랑 간담회같은 자리라고 하셔서 크게 부담없이 갔는데..

최종 합격자 4명이 들어갔는데 한명씩 취미를 물어보시더니.. 취미가 시 쓰기라고 대답한 사람한테 시를 지어보라고 하셨다..

와 또 당했다... '내 취미는 티레이더 배틀이에요'라고 해야지 생각하는 순간 대표님이 대만에 있는 어머니와 관련된 시를 읊어주셨다.(참고로 티레이더 배틀은 유안타증권의 주식 관련 게임이다)

이런 게 ceo 의 빌드업인가.. 또 하나 배운 삐리리뽀옹. 나머지 최종 간담회 내용은 기억이 안 나므로 더 적지는 않겠다.

 

이렇게 최종 합격하게 된 삐리리뽀옹.

하지만 자소서 쓸 때의 마음과는 다르게 달콤한 회사들 전형이 아직 남아 최종 입사를 고민하다 결국 포기하게 된다...

 

결국 좋은 방향으로 흘러갔다고 생각하지만 당시 입사 포기하고 좌절하며 흘렸던 내적 눈물의 양은 어마어마했다..

그 이야기는 다른 글에서 써보도록 하겠다..

 

유안타 면접을 통해 배운 것은..

1. 면접 전에는 함부로 딴짓하지 말자!

2. 면접 예상 질문 리스트는 정말 중요하다! 다양한 시각으로 자소서를 바라보며 작성해보도록 하자

 

회사 적응하기 바빠 블로그 관리를 잘 못했습니다...

 

------------------------------------------------

 

ibk 형제에게 뼈아픈 패배를 맞이한 삐리리뽀옹...

 

그날의 기억을 잊지 않기 위해 ibk 기업은행 면접 때 입은 츄리닝을 입고, 아침 일찍 일어나 코딩테스트와 면접을 준비하게 된다..

 

그 결과, 어찌어찌 11번가의 코딩테스트를 뚫고 1차 면접에 응시할 수 있는 기회를 얻게 됐다.

 

*참고로 코딩테스트는 2문제 정도 나왔고 그렇게 어려운 문제는 아니었던 걸로 기억한다.

 

절치부심하며 같은 실수를 반복하지 않기 위해 열심히 면접 준비를 했는데 알고 보니 sw 개발이 아닌 System Engineer 직군에 지원했던 것.

 

원서 쓸 때부터 사실 불합이 정해져 있던(그렇게 믿고 싶다) 도전... 하지만 기적은 기대가 없을 때 일어난다.

 

11번가의 면접은 화상 면접으로 진행됐고, pt 면접과 기술 면접으로 진행됐다.

 

pt 면접은 주제를 주고 40분인가? 50분인가? 준비 시간을 거쳐 10~15분 정도 발표를 했던 것 같다. 발표가 끝나면 바로 발표 질문 + 자소서, 기술 등 질문을 했다.

 

내가 받았던 주제는 정확하게 밝힐 수는 없지만 대충 하루만 트래픽이 확 늘어나는 이벤트가 있는데 이때 서버 트래픽을 어떻게 관리할 거냐 하는 지금 생각해보면 인프라 지원자라면 당연히 알아야 하는 기본적이고 대표적인 문제였다.

 

무식하면 용감하다.

문제가 주어지자마자 밥 아저씨에 빙의한 삐리리뽀옹. 일필휘지로 a4 용지에 무수히 많은 서버를 그리기 시작했다...

 

 

무한의 서버를 그린 이유...

 

삐리리뽀옹의 해답은 용산 전자상가에서 남는 서버를 단 하루만 빌려다 쓰는 것...!

 

 

은 농담이고, 사실 클라우드 가상 서버를 일시적으로 여러대를 사용하자는 의도로 그런 식으로 그렸다.

 

L4 스위치의 존재조차 알리 없던 삐리리뽀옹... 의식과 무의식의 경계에서 들었던 네트워크 수업 내용을 끄집어내어 서버들 앞에 라우터 하나를 그리고 그 많은 서버들과 1:N 연결을 해버린다.

 

 

대망의 발표 시간..

 

자신의 떨리는 목소리를 1과 0의 디지털 신호로 바꿀 수 있어 다행이라는 엉터리 생각을 하며 발표를 마친 삐리리뽀옹...

그래도 발표를 끝냈다는 안도의 한숨을 쉬는 삐리리뽀옹에게 면접관님은 아래와 같이 말씀하셨다.

"인프라 서버에 대해 하나도 모르시는 것 같네요."

 

 

이전 면접들에서는 실력 때문이 아니라 예의와 개념이 없어 떨어진 거라고 믿고 싶던 삐리리뽀옹에게 면접관님의 이 한마디는 삐리리뽀옹의 마지막 자존감을 산산조각 내버렸다.

 

하지만 포기는 배추를 셀 때나 쓰는 법...ㅎㅎ

그래... 난 삐리리뽀옹... 이런 때야말로 불타오르는 면접자지...

이어지는 자소서 및 기술 질문에서 아직 봉인된 자신의 실력을 보여주고 전세를 뒤집겠다 마음먹는다.

 

30분 정도 시간이 지난 후, 거의 모든 질문에 두루치기를 당한 채 여지없이 쓰러져버린 삐리리뽀옹...

 

포기는 배추를 셀 때나 쓰는 게 아니라 배추를 셀 때도 쓰는 거였구나.. 깨달음을 얻은 삐리리뽀옹은 면접은 포기하고 면접관님께 "다음에는 어떻게 해야 면접 더 잘 볼 수 있을까요?" 질문하게 된다.

 

면접관님은 "면접이 취업 컨설팅처럼 되어버렸네요.. 하하.." 하시면서  진심어린 걱정과 조언을 해주셨다...

 

죄송하게도 그때의 조언은 지금 다 잊어버렸지만, 당시에는 아주 감명받고 어떻게 it 취업 준비를 해야겠다~~ 하는 깨달음을 얻게 되었던 것 같다...

 

츄리닝에 밟힌 첫 번째 취업 도전... 아침 새소리에 찢긴 두 번째 취업 도전...

 

세 번째 도전은 실력으로 깔리며 11번가 1차 면접 광탈로 마무리짓게 된다...

 

11번가 면접에서 얻은 교훈

1. 원서 쓸 때는 아무 직무나 막 쓰지 말고 내가 할 수 있는 직무를 쓰자...

2. 인프라(서버고 네트워크고)는 학교에서 배운 이론만으로는 힘들다. 추가적인 공부가 필수적이다!

 

 

 

1. 문제

1) 문제 링크

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

 

2281번: 데스노트

첫째 줄에 n(1 ≤ n ≤ 1,000), m(1 ≤ m ≤ 1,000)이 주어진다. m은 노트의 가로 칸의 개수(폭, 너비)이다. 다음 n개의 줄에는 각 사람의 이름의 길이가 노트에 적어야 할 순서대로 주어진다. 각 길이는 m

www.acmicpc.net

 

2) 설명

대강 요약하면 데스노트에 이름을 쓸 때 각 줄별로 뒤의 여백을 구하는 문제다.

각 줄에 이름을 이어서 쓰거나 새로운 줄에 쓸 수 있다. 다만 이름이 중간에 잘리면 그줄에 이어서 못 쓰고 반드시 다음 줄에 새로 써야 한다.

또한 이름 사이에는 한 칸씩 띄어야 한다.

이때 각 줄의 마지막 이름 뒤에 오는 빈 칸들의 제곱의 합을 최소화하는 문제다.

이때 맨 마지막 줄의 빈 칸은 계산할 때 제외한다.

 

2. 풀이

1) 알고리즘

    : DP

 

2) 풀이 설명

dp 배열에 대한 정의는 다음과 같다.

dp[ i ] : i번째 이름을 새로운 줄에서 시작했을 때, 그 뒤의 이름들로 데스노트를 채워서 얻을 수 있는 빈칸제곱합의 최소값

(말이 좀 어려울 수 있는 것 같다..)

 

아래 문제의 예시를 살펴보면

n = 11, m = 20

index value
0 7
1 4
2 2
3 3
4 2
5 5
6 1
7 12
8 7
9 5
10 6

 

dp[10]은 새로운 줄에 index = 10인 이름을 쓰고 (이러면 20 - 6 = 14만큼의 공백이 남는다) 뒤에 더 올 이름이 없으므로 14의 제곱인 196이 된다. 다만 이 경우는 마지막 줄이라 계산하지 않으므로 0이 된다..

 

dp[9]는 index = 9인 이름을 새 줄에서 시작했을 때의 최소값을 구하면 되는 거다. name[9]는 5글자이므로 뒤에 공백 15칸이 남는다. 그럼 이때 뒤에 남은 name[10]을

1. 이어서 붙여쓸 건지

2. 새 줄에 쓸 건지

에 따라 값이 달라지므로 이 두 가지 경우 중 최소값을 쓰면 된다.

1번처럼 name[10]을 이어서 붙여쓸 경우에는 남은 15칸의 공백 중 띄어쓰기 1칸, 10번째 이름 6칸이 추가로 쓰여지므로 15 - 1 - 6인 8만큼의 공백이 뒤에 남는다. 그러나 이 경우에는 해당 줄이 마지막 줄이 되므로 1의 결과값 후보는 64가 아닌 0이다.

2번처럼 name[10]을 새로운 줄에 쓸 경우에는 남은 15칸의 공백의 제곱인 225에 dp[10]을 더한 225가 결과값 후보가 된다.

결국 dp[9] = min(0, 225) = 0이 된다.

 

dp[8]도 구해보자.

dp[8]은 index = 8인 이름을 새 줄에 썼을 때의 최소값을 구하면 된다.

그럼 dp[8]은

1. name[9]를 새 줄에 띄어쓰는 경우 -> 결과값 후보 : (20 - 7)^2 + 0( = dp[9]) = 169

2. name[9]를 이어붙이고 name[10]을 새 줄에 쓰는 경우 -> 결과값 후보 : (20 - (7 + 5 + 1))^2 + 0( = dp[10]) = 49

3. name[9], name[10]을 모두 이어붙이는 경우 -> 결과값 후보 : 0

이므로 dp[8] = 0이 된다.

 

한 번은 0이 아닌 경우를 구해봐야 할 것 같아서 dp[7]이랑 dp[6]까지 값을 구해보면...(이미 이해 됐으면 굳이 안 봐도 될 것 같다...)

dp[7]은

1. name[8]을 새 줄에 띄어쓰는 경우 -> 결과값 후보 : (20 - 12)^2 + dp[8] = 64

2. name[8]은 이어붙이고 name[9] 부터 띄어쓰는 경우 -> 결과값 후보 : (20 - 12 - 1 - 7)^2 + dp[9] = 0

이므로 dp[7] = 0

이때 name[8], name[9]를 이어붙일 수는 없다..! 그러면 한 줄에 20을 넘어가기 때문에..

 

dp[6]은

1. name[7]을 새 줄에 띄어쓰는 경우 -> 결과값 후보 : (20 - 1)^2 + dp[9] = 361

2. name[7]을 이어붙이고 name[8]부터 새 줄에 쓰는 경우 -> (20 - 1 - 1 - 12)^2 + d[8] = 36

이므로 dp[6] = 36이 된다.

dp[7] 때와 마찬가지로 name[6], name[7], name[8]을 이어붙일 수는 없다. 1 + 1 + 12 + 1 + 7 = 22 > 20이기 때문이다.

 

이런 식으로 dp배열을 채워나가면 된다.

 

그렇게 구한 dp[0]은 name[0]을 새 줄에 썼을 때 최소의 결과값을 가지는 거다.

이게 우리가 구하는 값이 된다!(name[0]은 무조건 새 줄의 시작이므로..)

 

 

3. 코드

더보기
#include <iostream>
#include <vector>
#include <algorithm>
#include <climits>

using namespace std;

const int N_MAX = 1000;
int n, m;
vector<int> dp(N_MAX, INT_MAX);
vector<int> names(N_MAX, 0);

int solution(int idx){
	//계산한 적 있으면 바로 리턴
	if(dp[idx] < INT_MAX)
		return dp[idx];

	int remain = m - names[idx]; //뒤에 다음 이름을 이어붙일 수 있는지 계산하기 위한 변수

	for(int i=idx+1;i<=n && remain>=0;i++){
    	//i번째 이름을 계속 이어붙여가본다. 물론 줄을 넘지 않는 선에서..(remain >= 0)
		if(i == n){
        	//줄을 넘지 않고 모든 이름을 이어붙인 경우다.. 그러면 마지막 줄이라는 말이니까 무조건 dp[idx] = 0이 된다.
			dp[idx] = 0;
			break;
		}
		dp[idx] = min(dp[idx], remain * remain + solution(i)); //재귀 호출
		remain -= names[i] + 1; //names[i]를 이어붙였으므로 이름 사이의 빈 칸(1) + names[i] 길이만큼을 remain(남은 칸 수)에서 빼준다.
	}

	return dp[idx];
}

int main()
{
	ios::sync_with_stdio(0);
	cin.tie(0);
	cout.tie(0);
	
	cin >> n >> m;
	for(int i=0;i<n;i++)
		cin >> names[i];

	dp[n - 1] = 0;

	cout << solution(0) << endl;

	return 0;
}

 

 

4. 느낀점

오랜만에 풀어보는 재미있는 dp 문제였다!

'알고리즘 > 백준' 카테고리의 다른 글

[백준/7512] 연속하는 소수의 합  (0) 2021.09.20
[백준/1727] 커플 맞추기  (0) 2021.08.25
[백준/2110] 공유기 설치  (0) 2021.08.01
[BOJ/1034] 램  (0) 2021.07.27
[BOJ/7579] 앱  (0) 2020.12.29

1. 문제

1) 문제 링크

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

 

7512번: 연속하는 소수의 합

각 테스트 케이스마다 "Scenario i:"를 출력하고, 둘째 줄에 정답을 출력한다.

www.acmicpc.net

 

2) 설명

숫자 n_i들이 주어지면 각각 n_i 개만큼의 연속된 소수들의 합으로 만들 수 있는 최소의 소수를 구하는 문제다.

2. 풀이

1) 알고리즘

    : 에라토스테네스의 체, 슬라이딩 윈도우

 

2) 풀이 설명

 

일단 에라토스테네스의 체로 소수 배열(primes)을 구한다. 그리고 소수인지 아닌지 판별할 수 있는 isPrime배열까지채워넣는다.

사실 소수 구하는 코드는 기억을 더듬어 대강 한 거라 다른 풀이를 보는 게 더 나을 수도 있다.

 

이제부터 슬라이딩 윈도우로 문제를 풀면 된다.

먼저 각 케이스별로 구하는 답을 answer라고 한다.

 

이제 sumArray와 sumBeginIndex 배열을 이용해서 answer를 구해본다.

 

nArray[i] = 연속한 소수의 수

sumArray[i] = n_i개의 연속된 소수의 합으로 만든 소수

sumBeginIndex[i] = sumArray[i]의 소수를 만드는 연속된 소수들 중 첫번째 인덱스를 가리킨다.

 

예를 들어 nArray[i]가 3이면 sumArray와 sumBeginIndex에 가능한 값은 다음과 같다.

sumBeginIndex[3] 0 1 2
sumArray[3] 9 ( = 2 + 3 + 5 ) 근데 소수가 아니라 안 됨  15 ( = 3 + 5 + 7 ) 얘도 소수가 아니라 안 됨 23 ( = 5 + 7 + 11) 은 소수니까 ok

sumBeginIndex[3]에는 0, 1은 들어갈 수 없고 2부터 시작하게 된다.(소수 연속합이 소수여야 하므로)

 

그러면 그러면 이제 n_i별로 sumArray, sumBeginIndex를 구성할 수 있다.

 

첫 초기값을 구하고 슬라이딩 윈도우를 통해 계속 sumArray의 모든 원소가 answer와 같아질 떄까지 슬라이딩 + answer를 업데이트 해주면 된다.

 

이때 sumArray[i] < answer라면, sumArray[i[ 를 슬라이딩시킨다.(그 합이 소수가 될 때까지)

만약 sumArray[i] > answer라면, 더이상 해당 answer 값은 모든 n_i 개의 연속합으로 만든 공통의 소수가 될 수 없다... i개의 연속합으로 answer를 만들 수 없다는 말이기 때문이다..

 

앞서 말했듯 이런 식으로 sumArray와 sumBeginIndex, answer 값을 sumArray의 모든 값과 answer 값이 같아질 때까지 반복하면 된다!

 

 

3. 코드

더보기
#include <iostream>
#include <cmath>
#include <algorithm>
#include <vector>
#include <numeric>

#define MAX_VAL 10000000

using namespace std;

vector<bool> isPrime(MAX_VAL, true); // 해당 수가 소수인지르 나타내는 배열
vector<int> primes; // 소수만 있는 배열

// 에라토스테네스의 체로 소수 구하는 함수
void setPrimes(){	
	isPrime[0] = isPrime[1] = false;
	isPrime[2] = true;
	for(int i=2;i<MAX_VAL;i++){
		if(isPrime[i] == false)
			continue;
		
		primes.push_back(i);
		
		for(int j=i*2;j<MAX_VAL;j+=i){
			isPrime[j] = false;
		}
	}
}

// 모든 sumArray가 같은 값을 갖고 있는지 확인
bool isCorrect(vector<int> sumArray, int val){
	for(auto x : sumArray)
		if(x != val)
			return false;
	return true;
}

int main()
{
	ios::sync_with_stdio(0);
	cin.tie(0);
	cout.tie(0);
	
	setPrimes();

	int t;
	cin >> t;
	for(int i=1;i<=t;i++){
		int m;
		cin >> m;
		vector<int> nArray(m, 0); // n_i 배열
		vector<int> sumArray(m, 0); // n_i만큼 연속된 소수의 합을 가진 배열(중요!! : 이 값은 소수여야 함)
		vector<int> sumBeginIndex(m, 0); // sumArray에 있는 연속된 소수의 합이 어디서부터 시작했는지를 가리키는 index의 배열

		//input
		for(int j=0;j<m;j++)
			cin >> nArray[j];

		//첫 sumArray와 sumBeginIndex 구하기
		for(int j=0;j<m;j++){
			sumArray[j] = accumulate(&primes[0], &primes[nArray[j]], 0);
			while(!isPrime[sumArray[j]]){ //구한 합이 소수인지 체크
				//소수가 아니라면 슬라이딩 윈도우로 증가
				sumArray[j] += primes[sumBeginIndex[j] + nArray[j]] - primes[sumBeginIndex[j]];//슬라이딩 윈도우로 다읍 값 더하고 맨 앞의 값 빼기 
				sumBeginIndex[j]++; //시작 인덱스 증가
			}
		}

		int answer = *max_element(sumArray.begin(), sumArray.end()); // answer 초기값 설정, 아마 min_element로 하든 뭐로 하든 sumArray 안의 값으로 하면 상관 없을 것 같다(어차피 아래 while문 통해서 업데이트 될 거라)
		
		while(!isCorrect(sumArray, answer)){ //sumArray 배열의 모든 값이 answer랑 똑같다면 정답을 구한 거임
			for(int j=0;j<m;j++){
				if(sumArray[j] < answer){
					//sumArray[j] 값이 answer보다 작으면 슬라이딩 윈도우로 beg ~ end -> beg+1 ~ end+1로 합 증가
					//이걸 새로 구한 소수의 연속합이 소수가 될 때까지 반복
					//초기값 구할 때와 달리 do while문인 이유는 얘는 이미 소수의 연속합이 answer보다 작기 때문에 최소한 한 번은 무조건 업데이트를 해줘야 하기 때문이다. 주석처리된 코드처럼 sumArray[j] += ~~~~~~; while(!isPrime[sumArray[j]]){~~~}로 해도 되지만 슬라이딩 윈도우하는 코드가 중복돼서 그냥 do while문으로 해줬다
					/*
					sumArray[j] += primes[sumBeginIndex[j] + nArray[j]] - primes[sumBeginIndex[j]];		
					sumBeginIndex[j]++;
					while(!isPrime[sumArray[j]]){
						sumArray[j] += primes[sumBeginIndex[j] + nArray[j]] - primes[sumBeginIndex[j]];		
						sumBeginIndex[j]++;
					}
					*/
					do {
						sumArray[j] += primes[sumBeginIndex[j] + nArray[j]] - primes[sumBeginIndex[j]];
						sumBeginIndex[j]++;
					} while(!isPrime[sumArray[j]]);
				} else {
					//sumArray 중에 answer보다 큰 값이 있으면 answer 값 업데이트
					answer = sumArray[j];
				}
			}
		}
		cout << "Scenario " << i << ":\n";
		cout << answer << "\n\n";
	}
	return 0;
}

 

 

4. 느낀점

개인적으로 소수 문제는 별로 선호하지 않는다.. (어렵기 때문 ㅎㅎ)

그래도 머리 싸매고 풀어내니까 기분이 좋더라..

근데 정작 내가 푼 알고리즘을 설명을 못 하겠다..

너무 복잡하게 푼 게 아닐까 싶어서 맞은 분들의 다른 풀이를 봤는데... 잘 모르겠더라..ㅎㅎㅎ

많이 부족함을 느낀다..

'알고리즘 > 백준' 카테고리의 다른 글

[백준/2281] 데스노트(1차원 dp)  (2) 2021.10.01
[백준/1727] 커플 맞추기  (0) 2021.08.25
[백준/2110] 공유기 설치  (0) 2021.08.01
[BOJ/1034] 램  (0) 2021.07.27
[BOJ/7579] 앱  (0) 2020.12.29

+ Recent posts