이번시간에 라즈베리파이 카메라로 동영상을 스트리밍 하는 방법에 대해 알아보겠습니다.

라즈베리파이의 스트리밍 기술스택을 알아보면서 motion, G-streamer, mjpg-streamer 등 많은 방법들이 있음을 알게되었습니다.

이 중에서 mjpg-streamer라는 패키지를 이용해서 동영상을 스트리밍 해보겠습니다.

 

일단 패키지 설치 전 다음 두 명령어로 패키지를 업데이트/업그레이드 해줍니다.

 

sudo apt-get update

sudo apt-get upgrade

 

스트리밍 패키지를 깃허브에서 클론 해 와야하기 때문에 저장할 폴더를 만들어주고 이동한 뒤 패키지를 클론합니다.

mkdir ./mjpg

cd mjpg/

git clone https://github.com/jacksonliam/mjpg-streamer.git 

다운이 완료 됐으면 받은 폴더의 mjpg-streamer/mjpg-streamer-experimental/로 이동합니다.

cd mjpg-streamer/

cd mjpg-streamer-experimental/

 

아래 명령어를 입력하여 컴파일 및 설치를 해줍니다.

sudo apt-get install cmake

 

이제 mjpg-streamer에 필요한 패키지를 설치하는데, 이부분은 다른분들의 참고를 했는데 될 때도 있고 안될 때도 있는 것 같습니다. 나중에 확인해도 문제가 없었기 때문에 일단 명령어를 입력해봅니다.

 

sudo apt-get install python-imaging (저는 이 패키지 설치에서 에러났지만 결과에 영향이 없었습니다.)

sudo apt-get install libjpeg-dev

 

이제 컴파일 해줍니다.

make CMAKE_BUILD_TYPE=Debug

완료되었습니다. 컴파일이 정상 완료되었으니 이제 mjpg-streamer를 설치합니다.

 

sudo make install

패키지 설치는 모두 끝났고 이제 홈 디렉토리로 돌아와 쉘 편집기를 열어줍니다.

cd ~

sudo nano mjpg.sh

적혀있는 코드를 아래와 같이 수정합니다. 포트는 사용하지않는 8091를 사용했습니다.

fps 는 디폴트로 5가 설정되어있는데 너무 끊기기 때문에 10정도로 맞춰줬고(전 나중에 15로 바꿔줬어요) -vf옵션으로 상하 반전으로 맞췄습니다.

fps를 높이고 -x,-y 가로세로 폭을 줄여주니깐 화질이 비교적 매끄럽게 나오더라구요.

 

명령어 옵션은 아래 그림을 참고해주세여

이제 아래 명령어로 스트리밍을 실행해봅니다. 

sh mjpg.sh

명령어를 입력하면 아래와 같은 화면이 뜨면서 스트리밍 서버가 실행중임을 알 수 있습니다.

이제 웹에서 ip주소:8091(아까 지정한 포트넘버)를 입력해보겠습니다. 아래화면이 떠야 정상입니다.

왼쪽 배너에서 stream을 클릭해주면 실시간 스트리밍 화면을 볼 수 있습니다.!!

15fps로 맞춰놨는데 엄청 부드럽진 않습니다. 카메라 사양 차이도 있을 것 같네요.

스트리밍을 중단하고 싶으면 아까 스트리밍을 실행시켰던 cmd창에 ctrl+Z를 입력하면 됩니다.

바로 스트리밍을 동작 시키면 프로세스 간 충돌이 일어날 수 있어서 에러가 납니다.

cmd창에 ps명령어로 지금 돌아가고있는 프로세스 목록을 확인하고

아래 명령어로 아직 종료되지 않은 1649 PID를 종료합니다.

 

kill -9 1649

 

이제 다시 확인해보면 지워졋죠?

아닙니다.(defunct는 좀비프로세스로 아직 완전히 종료되지않고 떠돌고 있는 상태의 프로세스입니다.)

mjpg-streamer 프로세스를 종료시키는게 아니라 sh 프로세스(1648번)를 종료해야합니다.

kill -9 1648

sh프로세스와 mjpg_streamer 프로세스가 같이 종료되었습니다.

이제 다시 쉘 명령어로 스트리밍을 시작할 수 있습니다. 

 

참고로 아까 웹사이트에 ip, 포트넘버를 입력하면 어떤 창이 하나 떴잖아요?

이거를 안띄우고 바로 스트리밍 화면을 보고싶다면 웹 주소에 ip주소:포트넘버/?action=stream 꼴로 작성하면됩니다.

ex) 162.178.31.2:8091/?action=stream

 

엔터치면 바로 스트리밍 화면이 뜨는 걸 확인할 수 있습니다.

다시 ps -> kill 명령어로 프로세스를 종료하여 사용을 마치도록합니다.

 

이상입니다!

 

 

 

요 근래에 서버/DB 사용을 위해 파이어베이스를 다뤄보고 있는데 여러모로 쓸만 한 것 같습니다. 

 

이번시간에는 라즈베리파이 카메라 v2로 주기적으로 사진을 촬영하고 이미지를 파이어베이스의 storage에 저장하는 코드를 작성해보겠습니다.

처음에 파이어베이스의 realtime database와 firestore database, 그리고 storage의 차이가 뭔지 몰랐는데 이미지파일은 DB에 저장이 안되는 것 같습니다.

(검색해보니까 이렇게 나오네요)

 

이제 순서대로 이 예제를 실행해보겠습니다.

라즈베리파이 카메라 연결

일단 라즈베리파이에 카메라를 연결해야합니다. 연결하고 라즈베리파이 configuration->interface에서 카메라를 enable 시켜준 뒤 잘 연결이 되었는지 아래 명령어로 확인합니다.

만약 supported 값은 1인데 detected가 0이라면 정상적으로 연결되지 않은 것입니다.

 

vcgencmd get_camera

 

그리고 firebase-admin 패키지를 설치하고 주기적으로 사진을 찍는 스케쥴을 관리하기 위해 스케줄 패키지를 설치해줍니다.

 

sudo pip3 install firebase-admin

 

sudo pip3 install schedule

 

이제 파이어베이스 홈페이지에서 간단하게 설정을 해줘야 하는데, 우리가 필요한 건 프로젝트 ID, 비공개 키, 스토리지 주소입니다.

차례대로 설정단계를 알아보겠습니다.

 

파이어베이스 프로젝트 생성

파이어베이스 storage생성 전 프로젝트 생성단계는 간단하므로 넘어가겠습니다. 프로젝트 ID는 프로젝트 생성 후 프로젝트 목록을 보시면 프로젝트 이름과 아래에 작게 아이디가 적혀있습니다.

파이어베이스 Admin SDK 키 생성

이제 키를 발급받아야하는데, 파이썬에서 프로그래밍으로 파이어베이스와 연동하기 위해 일종의 자격 증명서 같은 전용 "키"의 역할을 합니다.

프로젝트로 들어간 뒤 왼쪽 배너의 톱니바퀴-> 프로젝트 설정으로 들어갑니다. 파이썬을 사용하므로 구성 스니펫을 파이썬으로 체크한 뒤 비공개 키를 생성합니다. 키를 다운받아놓고 본인이 잘 기억할만한 폴더에 저장해 둡니다.(까먹거나 잃어버리면 안됩니다..;)

라즈베리파이에서 이 키를 사용해야 하므로 이제 그 키를 라즈베리파이의 디렉토리에 복사를 해야합니다.

삼바를 통해 json파일을 넘겨주고 아무 디렉토리에 저장시켜줍니다.

파이어베이스 storage생성

왼쪽 배너에서 storage를 클릭하고 새 스토리지를 생성하는데, 이 때 보안규칙, 위치설정 등은 기본 디폴트로 진행합니다.

완료를 누르면 "버킷 생성중" 메시지가 뜨고 생성이 완료됩니다. 창을 보면 ~~appspot.com 주소가 있는데 파이어베이스 스토리지의 주소라고 보시면됩니다.

 

이제 라즈베리파이에서 파이어베이스 연동을 위해 필요한 프로젝트ID, 비공개 키, 스토리지 주소까지 모두 준비가 완료되었습니다. 

라즈베리파이 코드 작성 및 실행

자칫 헷갈릴 수 있으므로 코드 작성 전에 코드에 필요한 정보들을 나열하고 넘어가겠습니다. 

1. 프로젝트 ID : 프로젝트 생성 후 프로젝트 목록에 나와있음 

2. Admin SDK 키 : .json키 파일을 삼바를 통해 라즈베리파이 디렉토리에 저장합니다.

저는 /home/pi/Downloads(생성폴더)에 저장시켜 놨습니다.

3. 스토리지 주소 : 파이어베이스 storage에 들어가면 gs://키정보.appspot.com 이 있는데 이 정보도 이용합니다.

4. 스토리지 디렉토리 이름 : 프로그래밍으로 본인이 지정한 이름의 폴더를 파이어베이스 저장소에 만들 수 있습니다.

5. 사진 찍고 저장할 디렉토리 이름 : 주기별로 사진을 찍고 저장할 디렉토리입니다. 저는 /home/pi/image_store로 만들어주었습니다.

 

이제 코드를 살펴볼 차례입니다. 기본적인 틀은 다른분들의 코드와 공식 문서를 참고하여 작성했습니다.

웬만한 중요 부분은 주석으로 보충 설명하였고 64~69행 설정으로 사진을 찍고 삭제하는 주기를 조절할 수 있습니다.

파일명은 현재 년/월/일로 시/분/초로 나타냈습니다.   

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
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
# _*_ coding: utf-8 _*_
from picamera import PiCamera
from time import sleep
import datetime
import sys, os
import requests
import firebase_admin
from firebase_admin import credentials
from firebase_admin import storage
from uuid import uuid4
import schedule
 
PROJECT_ID = "project-8965d"
#my project id
 
cred = credentials.Certificate("/home/pi/Downloads/(키 이름).json"#(키 이름 ) 부분에 본인의 키이름을 적어주세요.
default_app = firebase_admin.initialize_app(cred,{'storageBucket':f"{PROJECT_ID}.appspot.com"})
#버킷은 바이너리 객체의 상위 컨테이너이다. 버킷은 Storage에서 데이터를 보관하는 기본 컨테이너이다.
bucket = storage.bucket()#기본 버킷 사용
 
def fileUpload(file):
    blob = bucket.blob('image_store/'+file#저장한 사진을 파이어베이스 storage의 image_store라는 이름의 디렉토리에 저장
    #new token and metadata 설정
    new_token = uuid4()
    metadata = {"firebaseStorageDownloadTokens": new_token} #access token이 필요하다.
    blob.metadata = metadata
 
    #upload file
    blob.upload_from_filename(filename='/home/pi/image_store/'+file, content_type='image/png'#파일이 저장된 주소와 이미지 형식(jpeg도 됨)
    #debugging hello
    print("hello ")
    print(blob.public_url)
 
def execute_camera():
    
    #사진찍기
    #중복없는 파일명 만들기
    basename = "smr"
    suffix = datetime.datetime.now().strftime("%Y%m%d_%H%M%S"+ '.png'
    filename = "_".join([basename, suffix])
 
    camera = PiCamera()
    camera.resolution = (640480)
    camera.start_preview()
    #이미지에 텍스트를 새겨 넣자.
    camera.annotate_text = "Smart Mirror"
    camera.annotate_text_size = 20
    sleep(5)
    #사진을 찍어서 저장한다. 파일의 중복되지 않도록 날짜시간을 넣어서 만듬
    camera.capture('/home/pi/image_store/' + filename)
    #사진 파일을 파이어베이스에 업로드 한다.
    fileUpload(filename)
    #로컬 하드의 사진을 삭제한다.
    camera.stop_preview()
    camera.close()
 
#메모리 카드의 파일을 정리 해 주자.
def clearAll():
    #제대로 할려면 용량 체크 하고 먼저 촬영된 이미지 부터 지워야 할것 같지만 여기선 폴더안에 파일을 몽땅 지우자.
    path = '/home/pi/image_store'
    os.system('rm -rf %s/*' % path)
 
 
#10초 마다 실행
schedule.every(10).seconds.do(execute_camera)
#10분에 한번씩 실행
#schedule.every(10).minutes.do(execute_camera)
#매 시간 마다 실행
schedule.every().hour.do(clearAll)
#기타 정해진 시간에 실행/매주 월요일에 실행/매주 수요일 몇시에 실행 등의 옵션이 있다.
 
 
while True:
    schedule.run_pending()
    sleep(1)
 
 
 
cs

 

이제 실행해봅니다. 위 코드를 test.py라는 이름으로 작성했다고 한다면 다음처럼 실행하면됩니다.

sudo python test.py 

 

주의할점으로 제 환경 기준으로 커맨드 창에서 코드를 작성하고 실행해보니 계속 오류가 떴었습니다.

No module name firebase_admin 이라는 오류가 뜨면 sudo pip install firebase_admin으로 다시 깔아주면(파이썬3버전이 아닌 1버전) 오류는 사라집니다. 

 

여기까지 진행하고 정상 진행이 되면 상관없으나 에러가 나시는 분들은 당황하지 마시고  화면 상단의 산딸기 모양을 클릭하고 개발 탭에서 토니IDE에 소스를 복붙해서 실행해봅니다. (아마 잘 되실겁니다.) 토니 IDE는 기본으로 깔려있고 그냥 가벼운 비쥬얼 스튜디오라고 생각하시면됩니다.

이제 다시 실행해봅니다 !!

 

출력되는 "hello"는 제가 그냥 정상작동되는지를 확인하기 위해 넣은 코드입니다. 잘 작동한다면 이렇게 출력되겠죠??

20초동안 두 장만 촬영하고 프로그램을 중지 해 보겠습니다.

이제 파이어베이스 storage에 정상적으로 저장되었는지 볼까요??

 

이렇게 이미지 업로드 폴더가 생겼고

클릭해보면 두장의 사진이 잘 저장되어있음을 알 수 있습니다~~

아무거나 클릭해보면 사진화면이 잘 나오는걸 확인할 수 있어요.(TMI: 카메라에 비친 인공눈물 박스)

 

 

안드로이드와 연동하는 시스템을 목표로 파이어베이스를 사용하시는 분들은 위 그림 오른쪽 처럼 사진파일의 메타 데이터들도 쉽게 이용할 수 있습니다.

관련 예제를 본 것 같은데 다음에 한번 시도해 보겠습니다.

 

이상입니다~

 

 

이번시간에는 라즈베리파이의 웹서버 사용 및 간단한 웹 페이지 구축을 해보고 웹서버를 데스크탑(외부)환경에서 접근하는 방법에 대해 알아보겠습니다.

 

일반적으로 공유기 설정을 통한 포트 포워드 방식이 아닌, 작은 프로젝트에서 간이로 사용하는 방법임을 말씀드립니다.

 

먼저, 실습에 사용할 웹서버를 알아보겠습니다.

 

라즈베리파이에서 웹서버를 구축하기 위해 다양한 방법이 존재합니다.

 

아파치, AWS, Nginx 등 많은 웹서버 구축 방법이 존재하는데, 이번시간에 알아볼 웹서버 환경은 "CherryPy" 입니다.

 

체리파이는 파이썬 프로그래밍 언어를 사용하는 객체지향 웹 프레임워크입니다.

다른 WAS, 프레임워크들에 비해 간단하고 신속하지만, 낮은 수준을 유지하고 오래되서 많이 쓰이진 않습니다. 

 

이제 설치단계부터 하나씩 알아보겠습니다.

 

우선 cmd창에 아래 명령어로 체리파이를 설치해줍니다.

 

sudo pip3 install cherrypy

 

이제 잘 설치되었는지 확인해야합니다.

소스코드작성은 라즈비안에 내장된 IDE인 Thonny를 쓸 것 입니다.

Thonny 실행 화면에서 상단의 Tools -> Manage packages.. 를 클릭합니다.

아래와 같이 패키지가 잘 뜨면 설치가 정상적으로 완료된 것입니다.

이제 간단하게 웹 브라우저에 텍스트를 찍어보겠습니다.

아래와 같이 소스코드 작성 후 상단의 시작 버튼을 클릭하면 쉘창에 서버가 시작되었다는 문구가 출력됩니다.

맨 하단의 두 줄을 보면 엔진서버가 127.0.0.1:8080이고 시작되었다고 나와있죠.

127.0.0.1 은 자기 pc의 IP주소, 즉 루프백 주소를 나타냅니다. 기본적으로 로컬 포트번호는 8080으로 지정되있습니다.

 

이제 라즈비안의 웹 브라우저를 키고 127.0.0.1:8080 를 입력하면 아래와 같이 문구가 뜨게됩니다.

서버를 멈추고 싶으면 실행 프로그램을 중지 시키면됩니다.

 

아래처럼 html 코드를 이용할 수도 있습니다.

1. static.html코드 작성

2. StaticPage.py작성

3. 결과

 

파이썬 언어 뿐만 아니라 기본적인 웹언어(html, css, js)를 모두 사용할 수 있습니다.

html로 기본 틀을 잡고 css로 디자인을 하는 등(ex) 부트스트랩)  모든 것이 가능합니다.

위의 예제 코드처럼 클래스 안에 html 코드를 작성 한 뒤 똑같이 cherrypy.quickstart(클래스 명)을 입력하면 웹에 정상적으로 출력됩니다.

 

아래는 weatherMap API를 이용하여 세계 도시의 기상정보를 웹에 출력한 화면입니다.

 

 

이제 본론으로 돌아와서 간단하게 외부환경에서 이 웹에 접근하는 방법에 대해 알아봅니다.

 

단순히 어떠한 설정 없이 데스크탑 크롬, 엣지, 익스플로어 등으로 127.0.1:8080을 입력하면 실행이 되지 않습니다.

 

이는 라즈베리-데스크탑의 망이 서로 다르기 때문인데 이는 포트포워딩 방법으로 외부방에서 내부방 접근을 허용하는 설정을 통해 해결할 수 있습니다.

 

우리는 이 방법을 쓰지않고 간단하게 외부에서 로컬 호스트로 접속하는 시도를 해보겠습니다.

이 방법은 내가 만든 프로젝트를 외부에서 접근하고싶을 때 간단하게 사용하는 방법입니다.

 

우선 라즈비안에서 웹 브라우저로 ngrok.com/download 에 접속하여 리눅스 버전 압축파일을 다운 받습니다.

cmd창에서 명령어로 다운받을 수 있지만 간혹 설치 에러가 발생하여 위 방법으로 진행하는 게 마음이 편합니다. 

다운을 받고 압축파일을 우클릭하여 압축을 풀어줍니다. 저는 똑같은 디렉토리에 압축을 해제했습니다.

실행파일이 정상적으로 저장되었음을 확인합니다.

이제 cmd창에서 파일 실행을 위해 파일이 저장된 디렉토리로 이동합니다.

(파일이 저장된 디렉토리로 이동하지 않으면 당연히 실행되지 않습니다.)

이제 "./ngrok http 8080" 를 입력합니다.

이 명령어는  ngrok을 실행하여 localhost에 8080포트를 열어 체리파이 index를 외부에서 접근하도록 한다는 의미입니다.

http 터널을 8080포트에 열어주기 위해 위 명령으로 실행하는 것입니다.

엔터 치고나면 프로그램이 진행되며 다음과 같은 정보들을 알려줍니다.

Session Expires의 7hours, 59munutes는 동작 시간이 최대 8시간임을 타나내는 것이고 빨간 박스부분이 포워딩된 웹 사이트의 주소가 됩니다.

이제 아까 위에서 보았던 날씨API 웹사이트 코드를 실행합니다. cherrypy를 이용하여 서버를 실행하게 되죠?

 

이제 위 사진에서 포워딩된 두 웹 주소 중 아무거나 데스크탑 환경의 크롬, IE, edge 등에서 띄워봅니다.

 

아래와 같이 잘 동작함을 알 수 있습니다!

(css를 적용하지 않고 html의 그리드로 수정했기 때문에 위에서 본 페이지와 디자인이 다릅니다.)

 

 

코딩테스트 대비를 위해 도움이 될만한 문제 추천 블로그가 있어서 이 단계대로 코테를 준비합니다.

참조 사이트: http://covenant.tistory.com/224

 

코딩테스트 대비를 위한 백준 문제 추천

코딩테스트 대비를 위한 백준 문제 추천 끝 없는 훈련만이 실전에서 흐트럼없이 정답을 향해서 움직일 수 있습니다. (Photo by Specna Arms on Unsplash) 작년 한 해 수많은 코딩테스트를 직접 경험하고

covenant.tistory.com

Part 1 준비운동 - 소수 (백준 2581)

문제 출처: https://www.acmicpc.net/problem/2581

 

2581번: 소수

M이상 N이하의 자연수 중 소수인 것을 모두 찾아 첫째 줄에 그 합을, 둘째 줄에 그 중 최솟값을 출력한다.  단, M이상 N이하의 자연수 중 소수가 없을 경우는 첫째 줄에 -1을 출력한다.

www.acmicpc.net

풀이

에라토스테네스의 체를 이용하면 되고, 20행에서 최솟값을 비교하는 min변수를 사용함으로써 소수의 최솟값을 구하기 위해 또 m부터 n까지 수 중 가장 작은 수를 구하기 위해 반복문을 돌려야 하는 불필요 연산을 방지할 수 있습니다. 

코드

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
#include<iostream>
using namespace std;
int arr[10001];
int main()
{
    int m, n, sum = 0;
    arr[0= 1, arr[1= 1;
    for (int i = 2; i <= 10001; i++)
        for (int j = i * i; j <= 10001; j += i)
        {
            if (arr[j] == 1)continue;
            arr[j] = 1;
        }
    cin >> m >> n;
    int min = 10001;
    for (int i = m; i <= n; i++) {
        if (arr[i] == 0)
        {
            sum += i;
            if (min > i)min = i;
        }
    }
    if (sum) {
        cout << sum << endl;
        cout << min << endl;
    }
    else
        cout << -1 << endl;
 
    return 0;
}
cs

 

결과

코딩테스트 대비를 위해 도움이 될만한 문제 추천 블로그가 있어서 이 단계대로 코테를 준비합니다.

참조 사이트: http://covenant.tistory.com/224

 

코딩테스트 대비를 위한 백준 문제 추천

코딩테스트 대비를 위한 백준 문제 추천 끝 없는 훈련만이 실전에서 흐트럼없이 정답을 향해서 움직일 수 있습니다. (Photo by Specna Arms on Unsplash) 작년 한 해 수많은 코딩테스트를 직접 경험하고

covenant.tistory.com

Part 1 준비운동 - 쉽게 푸는 문제 (백준 1292)

문제 출처: https://www.acmicpc.net/problem/1292

 

1292번: 쉽게 푸는 문제

첫째 줄에 구간의 시작과 끝을 나타내는 정수 A, B(1 ≤ A ≤ B ≤ 1,000)가 주어진다. 즉, 수열에서 A번째 숫자부터 B번째 숫자까지 합을 구하면 된다.

www.acmicpc.net

풀이

처음에 약간 헷갈렸던 게 a,b가 각각 1,1000일 때 길이가 1000인 배열만으로 충분할까? 였는데 

즉, 1, 22, 333, 4444  -- -- -식으로 가다보면 배열길이 1000이 한참 모잘라서 문제가 될 것 같았지만

되게 멍청한 생각이었던게.. a,b가 1,1000이면 첫번째 부터 1000번째 인덱스 까지만 구하면 되므로 상관이 없습니다.

14행을 주석처리 하고 제출하면 인덱스 범위를 초과할 수 있으므로 fail이 뜰 수 있으니 이것만 조심하면 될 것 같습니다.

코드

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
#include<iostream>
using namespace std;
int arr[1001];
int main()
{
    int a, b, sum = 0, k = 0;
    cin >> a >> b;
    int i, j = 0;
    for (i=1; i <=1000; i++)
    {
        for (j=1; j <=i; j++)
        {
            arr[k] = i;
            if (k >= 1000)break;
            k++;
        }
    }
    for (int i=a-1;i<b;i++)
    {
        sum += arr[i];
    }
    cout << sum << endl;
    return 0;
}
cs

 

결과

 

코딩테스트 대비를 위해 도움이 될만한 문제 추천 블로그가 있어서 이 단계대로 코테를 준비합니다.

참조 사이트: http://covenant.tistory.com/224

 

코딩테스트 대비를 위한 백준 문제 추천

코딩테스트 대비를 위한 백준 문제 추천 끝 없는 훈련만이 실전에서 흐트럼없이 정답을 향해서 움직일 수 있습니다. (Photo by Specna Arms on Unsplash) 작년 한 해 수많은 코딩테스트를 직접 경험하고

covenant.tistory.com

Part 1 준비운동 - 소수 찾기 (백준 1978)

문제 출처: https://www.acmicpc.net/problem/1978

 

1978번: 소수 찾기

첫 줄에 수의 개수 N이 주어진다. N은 100이하이다. 다음으로 N개의 수가 주어지는데 수는 1,000 이하의 자연수이다.

www.acmicpc.net

풀이

초보자 입장에서 풀고 한 단계 더 나아가 소수찾기 알고리즘 원픽 에라토스테네스의 체를 이용하여 풀어보았습니다.

결과적으로 30행에서 반복문의 arr[j]는 모두 소수가 아니기 때문에 이를 체크 해줌으로써 쉽게 소수를 걸러낼 수 있습니다.

에라토스테네스의 체에 대한 개념은 아래 링크를 통해 학습할 수 있습니다.

https://jow1025.tistory.com/12

 

코드

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
#include<iostream>
using namespace std;
int arr[1001];
int main()
{
    int t, i, num, cnt = 0;
    cin >> t;
    while (t--)
    {
        cin >> num;
            //솔루션1: 입력범위가 작으면 이대로 풀자.
        /*if (num > 1) {
            for (i = 2; i < num; i++)
            {
                if (num % i == 0)
                    break;
            }
            if (i == num)cnt++;
        }*/
 
        //솔루션 2: 입력범위가 크다싶으면 그냥 에라토스테네스의체 쓰자.
 
        //0과 1은 소수가 아니므로 1값으로 체크
        arr[0= 1, arr[1= 1;
        for (int i = 2; i < 1001; i++)
        {
            for (int j = i * i; j < 1001; j += i)
            {
                //소수가 아닌 경우 체크
                 arr[j] = 1;
            }
        }
        if (arr[num] == 0)cnt++;
    }
    cout << cnt << endl;
    return 0;
}
cs

 

결과

코딩테스트 대비를 위해 도움이 될만한 문제 추천 블로그가 있어서 이 단계대로 코테를 준비합니다.

참조 사이트: http://covenant.tistory.com/224

 

코딩테스트 대비를 위한 백준 문제 추천

코딩테스트 대비를 위한 백준 문제 추천 끝 없는 훈련만이 실전에서 흐트럼없이 정답을 향해서 움직일 수 있습니다. (Photo by Specna Arms on Unsplash) 작년 한 해 수많은 코딩테스트를 직접 경험하고

covenant.tistory.com

Part 1 준비운동 - N번째 큰 수 (백준 2693)

문제 출처: https://www.acmicpc.net/problem/2693

 

2693번: N번째 큰 수

첫째 줄에 테스트 케이스의 개수 T(1 <= T <= 1,000)가 주어진다. 각 테스트 케이스는 한 줄로 이루어져 있고, 배열 A의 원소 10개가 공백으로 구분되어 주어진다. 이 원소는 1보다 크거나 같고, 1,000보

www.acmicpc.net

풀이

이런 간단한 문제를 풀 때는 배열을 선언하여 매 tc마다 memset으로 0으로 초기화 해주기, comp 함수로 내림차순 정렬하기, 벡터를 이용하여 sort함수에

greater<int>()인자로 내림차순 정렬하기 등 간단한 연습을 해두면 좋을 것 같습니다. 

처음 제출한 코드가 52ms가 나오길래 10,11행을 추가하고 20행 endl을 '\n'으로 바꿔주니 0ms가 나왔습니다.

코드

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
#include<iostream>
#include<algorithm>
bool comp(const int a, const int b)
{
    return a > b;
}
using namespace std;
int main()
{
    cin.tie(0);
    cin.sync_with_stdio(false);
    int t;
    cin >> t;
    int arr[10];
    for (int i = 0; i < t; i++)
    {
        for (int j = 0; j < 10; j++)
            cin >> arr[j];
        sort(arr, arr + 10, comp);
        cout << arr[2<< '\n';
    }
    return 0;
}
cs

 

결과

 

코딩테스트 대비를 위해 도움이 될만한 문제 추천 블로그가 있어서 이 단계대로 코테를 준비합니다.

참조 사이트: http://covenant.tistory.com/224

 

코딩테스트 대비를 위한 백준 문제 추천

코딩테스트 대비를 위한 백준 문제 추천 끝 없는 훈련만이 실전에서 흐트럼없이 정답을 향해서 움직일 수 있습니다. (Photo by Specna Arms on Unsplash) 작년 한 해 수많은 코딩테스트를 직접 경험하고

covenant.tistory.com

Part 1 준비운동 - 최대공약수와 최소공배수 (백준 2609)

문제 출처: https://www.acmicpc.net/problem/2609

 

2609번: 최대공약수와 최소공배수

첫째 줄에는 입력으로 주어진 두 수의 최대공약수를, 둘째 줄에는 입력으로 주어진 두 수의 최소 공배수를 출력한다.

www.acmicpc.net

풀이

최대공약수는 유클리드 호제법으로 구하고 최소공배수는 n과 m을 곱한 값을 최대공약수로 나눈값입니다.

유클리드 호제법은 유용하고 코드가 간단하니 외워두시는 게 좋을 것 같습니다.

 

 

코드

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
#include<iostream>
using namespace std;
int GCD(int a, int b);
int main()
{
    int n, m;
    cin >> n >> m;
    //최대공약수->유클리드 호제법
    //최대공배수-> (n*m)/최대공약수
    int gcd = GCD(n, m);
    cout << gcd << endl;
    cout << (n * m) / gcd << endl;
    return 0;
}
int GCD(int a, int b)
{
    int c;
    while (b)
    {
        int c = a % b;
        a = b;
        b = c;
    }
    return a;
}
cs

 

결과

+ Recent posts