문제

 

입력

 

출력

 

 


 

 

문제 해결

반례에 주의하자!!

R : 배열을 reverse하는 연산

D : 배열의 앞 원소를 pop하는 연산

R이 홀수개이면 마지막에 한 번만 reverse 연산을 하여 시간 복잡도를 개선한다. 대신 flag를 세워 앞에서 pop 할 건지, 뒤에서 pop 할 건지 체크해야 한다.

 

반례는 크게 세 가지가 있는데, 코드 블럭 내에 적혀있다.

 

 

코드

#include <iostream>
#include <list>
#include <algorithm>

using namespace std;

int t, n, z, res;
string s1, s2;
list<int> v;

/*
* 반례
* 1. 빈 배열에서 pop하는 경우 : error 출력
* 2. 빈 배열에서 R하는 경우 : [] 출력
* 3. 모든 함수 수행 후 빈 배열이 되는 경우 : [] 출력
*/
string input() {

	int sum = 0;
	
	cin >> s1 >> n >> s2;

	for (int i = 1; i < s2.size(); i++) {

		if (s2[i] >= '0' && s2[i] <= '9')
			sum = 10 * sum + (int)(s2[i] - 48);		// '0' = 48, '9' = 57
		else if (s2[i] == ',' || s2[i] == ']') {
			if (!n) break;
			v.push_back(sum);
			sum = 0;
		}
	}
		
	return s1;
}

int solution(string s1) {	// error : 0, not error : 1, empty array : 2

	int s = s1.size();
	int c = 1, cnt = 0;
	bool flag = true;		// true일 때는 pop_front, false일 때는 pop_back

	for (int i = 0; i < s; i++) {
		if (s1[i] == 'R') {
			if (!v.size()) c = 2;	// 2. 빈 배열에서 R하는 경우 : [] 출력
			flag = !flag;
			cnt++;
		}
		else if (s1[i] == 'D') {
			if (!v.size()) return 0;	// 1. 빈 배열에서 pop하는 경우 : error 출력
			flag ? v.pop_front() : v.pop_back();
		
		}
	}

	if (cnt % 2) reverse(v.begin(), v.end());	// R 연산이 홀수개인 경우 마지막에 한 번만 reverse
	if (!v.size()) c = 2;			// 3. 모든 함수 수행 후 빈 배열이 되는 경우 : [] 출력
	return c;
}


int main() {

	cin >> t;

	while (t--) {
		v.clear();
		res = solution(input());
		int z = v.size();

		if (!res) {
			cout << "error" << '\n';
			continue;
		}
		else if (res == 2) {
			cout << "[]" << '\n';
			continue;
		}

		cout << '[';
		list<int>::iterator iter = v.begin();
		for (int i = 0; i < z - 1; i++) {
			cout << *iter << ',';
			iter++;
		}
		cout << *iter << ']' << '\n';

	}
}

'🎲 BOJ > 🥇' 카테고리의 다른 글

[C++] 백준 4256 : 트리  (0) 2023.08.06
[C++] 백준 20922 : 겹치는 건 싫어  (0) 2022.02.09
[C++] 백준 1072 : 게임  (0) 2022.02.08
[C++] 백준 2533 : 사회망 서비스(SNS)  (0) 2022.02.07

 

 

 

문제

 

입력

 

출력


 

 

문제 해결

 

pl, pr : 전위 순회의 첫 번째와 마지막

il, ir : 중위 순회의 첫 번째와 마지막

 

전위 순회에서 첫 번째는 무조건 현재 트리의 루트.

중위 순회에서 현재 트리 루트의 위치를 찾으면 그 왼쪽 pl까지의 개수는 왼쪽 자식트리 노드의 개수

같은 이유로 루트의 오른쪽 pr까지의 개수는 오른쪽 자식트리 노드의 개수

 

 

 

코드

#include <iostream>

using namespace std;

int pre[1001], in[1001];

// 전위 순회의 루트는 무조건 첫 번째
// 중위 순회에서 루트의 왼쪽 pl까지의 개수 = 왼쪽 자식트리 노드 개수
// 중위 순회에서 루트의 오른쪽 pr까지의 개수 = 오른쪽 자식 트리 노드 개수

void solution(int pl, int pr, int il, int ir) {

	if (pl == pr) {
		cout << pre[pl] << ' ';
		return;
	}

	for (int i = 0; i <= pr - pl; i++) {
		if (pre[pl] == in[il + i]) {
			solution(pl + 1, pl + i, il, il + i - 1);		// 왼쪽 트리
			solution(pl + i + 1, pr, il + i + 1, ir);		// 오른쪽 트리
			cout << pre[pl] << ' ';							// 루트 출력
		}
	}

}

int main() {
	int t, n;
	cin >> t;

	while (t--) {
		cin >> n;
		for (int i = 0; i < n; i++)
			cin >> pre[i];
		for (int i = 0; i < n; i++)
			cin >> in[i];

		solution(0, n - 1, 0, n - 1);
		cout << endl;
	}
}

'🎲 BOJ > 🥇' 카테고리의 다른 글

[C++] 백준 5430 : AC  (0) 2023.08.06
[C++] 백준 20922 : 겹치는 건 싫어  (0) 2022.02.09
[C++] 백준 1072 : 게임  (0) 2022.02.08
[C++] 백준 2533 : 사회망 서비스(SNS)  (0) 2022.02.07

 

 

 

모델

Diffusion Singing Voice Conversion(이하  Diff-SVC)은 음성 변환 기술의 한 형태이다. 여기서 말하는 음성 변환은 한 목소리의 특징을 다른 목소리로 변환하는 기술이다. 이는 보다 구체적으로는 음성의 높낮이, 음조, 발음 등을 변환하여 다른 사람의 목소리로 재생성하는 것을 의미한다.

 

SVC 모델은 content encoder를 학습시켜 input data로부터 content feature를 추출하고 conversion model을 학습시켜 추출한 content feature를 다른 feature로 교체한다. 보통 conversion model은 GAN 또는 regression model을 사용한다. GAN이 사용되는 경우 content feature로부터 파형을 바로 생성하고, regression model이 사용되는 경우 content feature를 spectral feature로 변환한 후 추가로 학습시킨 vocoder로 파형을 생성한다. Diff-SVC에서는 후자의 경우를 사용하며 conversion model로 regression model 대신 diffusion model을 사용한다. 이름에서 알 수 있듯이 diffusion model은 Diff-SVC의 기반 모델이다.

 

Diffusion model은 주로 image processing과 computer vision 분야에서 활용된다. Diffusion model은 이미지를 픽셀 단위로 처리하며, 각 픽셀은 주변 픽셀과의 상호 작용을 통해 정보를 전파한다. 이때 정보는 픽셀 간의 유사성을 기반으로 이루어지고 픽셀 값이 서로 유사한 경우 해당 정보를 주변 픽셀로 전달한다. 위 과정들이 반복적으로 진행되며 횟수를 거듭하면서 이미지의 노이즈가 감소하거나 복원되는 효과를 얻을 수 있다. 일반적인 SVC 기술은 딥러닝 신경망을 사용하여 입력 음성과 대상 음성간의 매핑 함수를 학습하지만 diffusion model을 활용하면 음성 특징을 시간적으로 확산시켜 input voice와 target voice 간의 상관 관계를 모델링한다.

 

Diffusion model에는 forward process와 reverse process가 있다. Forward process는 데이터에 점진적으로 약간의 Gaussian noise를 더하여 완전한 가우시안 분포로 만드는 과정이다. 반대로 reverse process는 Gaussian noise로부터 원데이터로 복구해가는 과정이다. 이는 각 process가 마르코프 체인(Markov chain)이기에 가능한 것이다.

 


 

데이터셋 준비

배경음이 없는, 노래 음성과 말하는 음성을 준비한다.

파일 형식은 샘플 전송률 44.1kHz, 16 bits 모노채널인 wav 파일로 변환한다.

각 파일의 최대 길이는 15초 정도를 넘지 않는 것이 좋으며 음의 높낮이가 다양하고 음성과 음성 사이에 공백이 적을수록 양질의 데이터이다.

데이터셋의 총합 길이가 길수록 자연스럽운 결과를 뽑아낼 수 있다. 통상 1시간 정도의 데이터셋이 효율적이다.

zip 파일로 압축한다.

 

 

 

 

모델 학습

https://colab.research.google.com/drive/1kiUvz1TrNJa_MOfOld7DHanv4gZsl7MN

 

Diff_SVC_training_notebook_colab_ver_.ipynb의 사본

Colaboratory notebook

colab.research.google.com

 

위 구글 코랩에서 자신의 구글 드라이브에 사본을 만든 뒤 차례로 실행해준다.

 

Check Setup

사용가능한 코랩 gpu 가속기를 확인한다. 기본 gpu 유형은 T4이며 구글 코랩 pro 구독시 제한된 컴퓨팅 단위로 A100 변경 가능하다. gpu 성능에 따라 학습 속도에 차이가 꽤 발생한다.

 

Mount Google Drive

구글 드라이브와 코랩을 연동한다. 데이터셋을 업로드하거나 학습된 모델을 저장하기 위해 구글 드라이브 연동이 필요하다.

 

Step 1: Install Diff-SVC

Diff-SVC 모델을 설치하는 과정이다. 디폴트로 UtaUtaUtau's Repo와 44.1kHz의 sample rate이 설정되어 있으며 이 설정은 변경할 필요없다.

 

Step 2: Decompress dataset

zip 데이터 파일을 압축해제하는 과정이다. singer_name란을 Shiki에서 자신이 사용할 이름으로 변경해주면 편하다.

코랩 좌측에서 폴더 아이콘을 클릭하여 업로드된 데이터셋 파일의 경로명을 찾아 dataset_location란에 넣어준다.

해당 스텝을 실행하기 이전에 구글 드라이브의 [내 드라이브] - [diff-svc] - [singer_name] 폴더 생성, 그 안에 singer_name.zip 이름으로 압축된 데이터셋 파일을 업로드 해둔다.

*singer_name은 literally singer_name이 아닌 앞서 변경한 singer_name란이다.

 

Training Options/Parameters

트레이닝 옵션을 설정하는 스텝이다.

pretrain_model_select에서는 원하는 pretrain model을 선택한다.

save_dir란에 /content/drive/Mydrive/diff-svc/singer_name 경로명을 넣어준다. 후에 학습할 때 2000번의 배수마다 학습된 모델이 저장되는 디렉토리이기도 하다. (최대 10개 저장, 이후 오래된 모델 순으로 드라이브 휴지통으로 이동된다.)

저장된 모델이 있고 그 모델의 학습을 이어서 수행하려면 resume_training_from_ckpt를 체크하고 해당 모델의 .ckpt파일 경로를 넣어준다. 다른 새로운 모델을 학습하는 것이라면 체크해제한다.

 

Training

학습을 진행하는 스텝이다. 앞서 적어놓았듯 2000번째마다 모델이 최대 10개까지 저장된다. 데이터셋이 길지 않다면 높은 step은 큰 효과가 없다. 1시간 남짓의 데이터셋이라면 80000 step에서 120000 step 사이 정도로 학습한 모델이 괜찮다.

 

 

모델을 이용하여 결과물을 추론하는 과정은 다른 코랩 링크에서 수행할 것이기 때문에 이후로는 따져보지 않아도 된다.

 

 

 

 

결과 추론

(아직 작성 중)

 

'🎵 Diff-SVC' 카테고리의 다른 글

diff-svc를 이용한 ai voice 학습  (0) 2023.05.07

 

 

 

 주피터 노트북 단축키


 

 

Command mode

 

파란색은 command mode 상태입니다. ([ESC] 또는 [Ctrl] + [m]을 눌러 진입)

a : 위에 새로운 셀 추가
b : 아래에 새로운 셀 추가


c : 셀 복사하기
v : 셀 붙여넣기
x : 셀 잘라내기
dd : 셀 삭제하기

p : 셀 아래에 붙여넣기

 

o : 실행결과 열기/닫기

m : Markdown으로 변경

y : Code로 변경

Shift + m : 선택 셀과 아래 셀과 합치기

Ctrl + s 또는 s  : 파일 저장

Enter  : 선택된 셀의 edit mode로 진입

 

 


 

 

 

Edit mode

 

초록색은 edit mode 상태입니다.

Ctrl + Enter : 입력 셀 실행 
Shift + Enter : 
입력 셀 실행 후 아래 셀로 이동 (없으면 새로운 셀 추가)
Alt + Enter : 
입력영역 실행 후 아래 새로운 영역 추가

 

Ctrl + a : 선택 셀의 코드 전체 선택

Ctrl + z : 선택 셀 내 실행 취소

Ctrl + / : 커서 위치 라인 주석처리

 

Tab : 지정된 모든 라인에 tab(4칸 들여쓰기) 적용

Shift + Tab : 지정된 모든 라인에 tab 취소

Shift + Ctrl + - : 커서 위치를 기준으로 셀 둘로 나누기

 

ESC : 선택된 셀의 command mode로 진입

 

 

주의사항 : training 할 때 /content/drive/MyDrive/diff-svc/[singer_name] 디렉토리 내에 [singer_name].zip으로 dataset 파일 넣어야 함. 경로와 zip 파일 이름이 같아야 한다.

 

 

 

https://www.youtube.com/watch?v=kSSTAP315LA

(2023.05.14일 동영상 비공개 처리됨)

 

- YouTube

 

www.youtube.com


https://github.com/coqui-ai/TTS/issues/2449

 

[Bug] RuntimeError: stft requires the return_complex parameter be given for real inputs · Issue #2449 · coqui-ai/TTS

Describe the bug When trying to fine-tune YourTTS with an LJSpeech formatted dataset after computing the encodings, this error appears. To Reproduce Run the your_tts recipe: https://gist.github.com...

github.com

Step 4: Pre-processing 단계에서,

RuntimeError: stft requires the return_complex parameter be given for real inputs, and will further require that return_complex=True in a future PyTorch release. 오류 해결

# 에러 경로의 functional.py 파일 line 641에 추가.
if not return_complex:
        return torch.view_as_real(_VF.stft(input, n_fft, hop_length, win_length, window,  # type: ignore[attr-defined]
                                           normalized, onesided, return_complex=True))


wav 포맷 변환

https://mp3cutterpro.com/kr/convert-m4a-to-wav

 

 

보컬 추출

https://studio.gaudiolab.io/gsep

 

Gaudio Studio | 가우디오 스튜디오

Instrument Separation & Noraebang

studio.gaudiolab.io

 

유튜브 오디오 분리

https://ko.onlymp3.to/197/

 

유튜브 MP3 변환기 및 다운 무료 온라인 - OnlyMP3

무료로 MP3에 유튜브 동영상을 변환하고 OnlyMP3에서 가장 높은 품질을 다운로드 할 수 있습니다. 온라인 MP3 변환기 및 다운 로더에 유튜브 최고.

ko.onlymp3.to

 

 

결과 추출에서 numpy 어쩌구 오류 날 경우, 런타임 - 런타임 다시 시작하기!!

diff-svc 디렉토리 하위에 batch_audio 폴더 만들고, 음원.wav 파일 넣기

config.yaml 파일도 [singer_name] 안에 있어야 한다.

'🎵 Diff-SVC' 카테고리의 다른 글

Diff-SVC(diffusion singing voice conversion)란?  (0) 2023.07.04

 

 

 

Jupyter Notebook?

  • Jupyter에서 제작한 Python용 통합 개발 환경으로, 현용 파이썬 개발 툴 중에서는 인기가 최상위입니다.
  • 웹브라우저에서 파이썬 코드를 작성하고 단계적으로 실행 가능합니다. (Google Colab과 비슷)

 


 

설치 방법

  • 주피터 노트북을 사용하기 위해서는 아나콘다(Anaconda)를 설치해야 합니다.

https://www.anaconda.com/data-science-platform

 

 

위 링크로 들어가서 Python version운영체제(Windows, macOS, Linux)에 맞게 다운로드 해주세요.

 

설치가 완료되면 윈도우 검색창에서 Jupyter Notebook를 찾을 수 있습니다.

 

이 프로그램을 클릭해서 실행시켜도 되지만 Anaconda Prompt에서 직접 jupyter notebook 명령어를 입력해서 실행시킬 수도 있습니다.

 

아래에 나와있는 URL 중 하나를 복사해서 붙여넣으면 Jupyter notebook에 연결됩니다.

단, 주의사항은 jupyter notebook을 사용하는 동안 jupyter notebook을 실행시킨 프롬프트 창은 종료시키면 안됩니다.

 


시작 폴더 위치 변경하기

 

① jupyter_notebook_config.py 파일에서 변경하기

아나콘다를 설치할 때 따로 경로를 설정해주지 않았다면 C:\Users\{사용자명}\... 어딘가로 시작 위치가 저장되어 있을 것입니다. 주피터 노트북의 시작 폴더 위치를 변경해주기 위해서는 Anaconda Prompt 창에서

jupyter notebook --generate-config 명령어를 입력해줍니다.

그러면 jupyter_notebook_config.py 파일의 위치를 알려줍니다. 해당 폴더로 가서 jupyter_notebook_config.py 파일을 열어줍니다.

 

notebook_dir 속성을 찾아서 원하는 폴더의 경로를 입력해줍니다. (Ctrl+F 키로 검색해서 찾을 수 있습니다.)

저는 시작 위치를 'C:\Users\ohsopp\Jupyter'로 정해주었습니다. 여기서 한가지 이상한 점이, \로 입력하면 시작 위치가 바뀌지 않고 //로 입력해야 바뀌더랍니다... 아무튼 바꿔줍니다,,

 

 

 

② Jupyter Notebook 속성 변경하기

Jupyter Notebook에서 [마우스 우클릭 + 속성]으로 들어갑니다.

대상칸에서 ~script.py 오른쪽에 "%USERPROFILE%/"를 지우고 자신이 설정한 경로를 넣어줍니다.

시작 위치칸도 지워줍니다.

설정이 끝났다면 마지막으로 확인 버튼을 눌러줍니다.

 

 

 

 

깔끔하게 비어있는 폴더로 시작 위치가 변경된 것을 볼 수 있습니다.

 

'🧩 Jupyter Notebook' 카테고리의 다른 글

주피터 노트북 단축키  (0) 2023.06.06

 

 

 

널 안정성이란?

널(null)이란 객체가 선언되었지만 초기화되지 않은 상태를 의미합니다. 객체는 데이터가 저장된 주소를 참조하므로 흔히 참조 변수라고 합니다. 데이터가 메모리에 저장되면 어디에 저장됐는지 알아야 이용할 수 있는데 이때 해당 메모리 위치를 식별하는 것이 주소입니다. 객체에는 주소가 저장되며 이 주소로 메모리에 접근해서 데이터를 이용합니다. 그런데 객체가 주소를 가지지 못한 상태를 나타냅니다.

 

널인 상태의 객체를 이용하면 널 포인트 예외(NullPointException)가 발생합니다. 널인 상태의 객체를 이용할 수 없다는 에러입니다. 이때 널 안정성이란 널 포인트 예외가 발생하지 않도록 코드를 작성하는 것을 말합니다. 당연히 널 포인트 예외가 발생하지 않도록 작성해야 하지만 중요한 것은 이런 노력을 누가 하는가입니다.

 

// 널 안정성을 개발자가 고려한 코드

fun main() {
	var data: String? = null
    val length = if (data == null) {
    	0
    } else {
    	data.length
    }
    println("data length : $length")
}
// 실행 결과

data length : 0

 

위 코드에서 String 타입의 data 변수를 null로 선언했습니다. data 변수에 대입한 문자열의 개수를 얻고자 length를 이용했는데 data가 null인 상태에서 data.length 코드를 실행하면 널 포인트 예외가 발생합니다.

 

따라서 if 문으로 data가 null인지 확인한 뒤 nulll이면 0을 반환하고 null이 아니면 data.length를 반환하게 작성했습니다. 이렇게 하면 data가 null이어도 널 포인트 예외가 발생하지 않습니다. 그런데 이렇게 널 안정성을 개발자의 몫으로 남겨두면 객체가 null인지 일일이 점검하는 코드를 작성해야 합니다. 하지만 위 소스를 다음처럼 작성할 수도 있습니다.

 

// 코틀린이 제공하는 널 안정성 연산자를 이용한 코드

fun main() {
    var data: String? = null
    println("data length : ${data?.length ?: 0}")
}
// 실행 결과

data length : 0

 

data가 null이면 0을 반환하고 null이 아니면 length를 이용해 문자열의 개수를 얻습니다. 앞선 코드와 똑같이 동작하지만 코드에서 직접적으로 null을 점검하지는 않습니다.

 

 

널 안정성 연산자

널 허용 연산자 ?

코틀린에서는 변수 타입을 널 허용(nullable)과 널 불허(not null)로 구분합니다. 변수에 null을 대입할 수 있는지를 선언할 때 타입으로 구분합니다. 아래 코드에서 data1 변수는 String 타입으로 선언했습니다. 이렇게 하면 널 불허로 선언하므로 data1 변수에 null을 대입하면 오류가 발생합니다. 그런데 data2 변수는 String 타입으로 선언했지만 타입 뒤에 ? 연산자를 추가했으므로 널 허용 변수가 되어 nulll을 대입할 수 있습니다.

// 널 허용과 널 불허

var data1: String = "ohsopp"
data1 = null	// 오류

var data2: String? = "ohsopp"
data2 = null	// 성공

 

널 안전성 호출 연산자 ?.

널 불허로 선언한 변수에는 null을 대입할 수 없으므로 널 포인트 예외를 신경 쓸 필요는 없지만, 널 허용으로 선언한 변수는 null을 대입할 경우 얼마든지 널 포인트 예외가 발생할 수 있습니다. 따라서 변수가 널인 상황을 고려해 프로그램을 작성해야 합니다.

 

다음 코드는 오류가 발생합니다. data 변수에 null이 아닌 데이터를 저장했더라도 변수를 널 허용으로 선언했으므로 언제든지 null이 대입될 수 있습니다. 이처럼 null이 대입될 수 있는 변수를 널 안정성을 고려하지 않고 작성하면 오류가 발생합니다.

// 널 포인트 예외 오류

var data: String? = "ohsopp"
var length = data.length	// 오류

 

따라서 널 허용으로 선언한 변수의 멤버에 접근할 때는 반드시 ?. 연산자를 이용해야 합니다. ?. 연산자는 변수가 null이 아니면 멤버에 접근하지만 null이면 멤버에 접근하지 않고 null을 반환합니다. ?. 연산자 덕분에 널 허용 변수에 null이 대입되더라도 멤버에 접근하지 않고 null을 반환합니다. 따라서 널 포인트 예외는 발생하지 않습니다.

// 널 안정성 호출 연산자 사용

var data: String? = "ohsopp"
var length = data?.length	// 성공

 

엘비스 연산자 ?:

엘비스 연산자는 ?: 기호를 말합니다. 이 연산자는 변수가 널이면 널을 반환합니다. 그런데 어떤 경우에는 변수가 널일 때 대입해야 하는 값이나 실행해야 하는 구문이 있을 수도 있습니다. 이때 엘비스 연산자를 이용합니다.

// 엘비스 연산자 사용

fun main() {
    var data: String? = "ohsopp"
    println("data = $data : ${data?.length ?: -1}")
    
    data = null
    println("data = $data : ${data?.length ?: -1}")
}
// 실행 결과

data = ohsopp : 6
data = null : -1

 

예외 발생 연산자 !!

!!는 객체가 널일 때 예외를 일으키는 연산자입니다. 객체가 널일 때 ?. 또는 ?: 연산자를 이용해 널 포인트 예외가 발생하지 않게 작성할 수도 있지만, 또 어떤 경우에는 널 포인트 예외를 발생시켜야 할 때도 있습니다. 이때 !! 연산자를 이용합니다.

// 예외 발생 연산자

fun some(data: String?): Int {
    return data!!.length
}

fun main() {
    println(some("ohsopp"))
    println(some(null))
}
// 실행 결과

6
Exception in thread "main" java.lang.NullPointerException

 

위 소스는 some() 함수에 문자열을 전달하면 오류 없이 정상적으로 실행되고, null을 전달하면 data!!.length 코드로 예외 메시지를 출력하는 것을 보여줍니다.

'📌 Kotlin' 카테고리의 다른 글

[Kotlin] List / MutableList 추가, 삭제  (0) 2022.02.19

 

 

 

문제

시골에 있는 태양이의 삼촌 댁에는 커다란 참외밭이 있다. 문득 태양이는 이 밭에서 자라는 참외가 도대체 몇 개나 되는지 궁금해졌다. 어떻게 알아낼 수 있는지 골똘히 생각하다가 드디어 좋은 아이디어가 떠올랐다. 유레카! 1m2의 넓이에 자라는 참외 개수를 헤아린 다음, 참외밭의 넓이를 구하면 비례식을 이용하여 참외의 총개수를 구할 수 있다.

1m2의 넓이에 자라는 참외의 개수는 헤아렸고, 이제 참외밭의 넓이만 구하면 된다. 참외밭은 ㄱ-자 모양이거나 ㄱ-자를 90도, 180도, 270도 회전한 모양(┏, ┗, ┛ 모양)의 육각형이다. 다행히도 밭의 경계(육각형의 변)는 모두 동서 방향이거나 남북 방향이었다. 밭의 한 모퉁이에서 출발하여 밭의 둘레를 돌면서 밭경계 길이를 모두 측정하였다.

예를 들어 참외밭이 위 그림과 같은 모양이라고 하자. 그림에서 오른쪽은 동쪽, 왼쪽은 서쪽, 아래쪽은 남쪽, 위쪽은 북쪽이다. 이 그림의 왼쪽위 꼭짓점에서 출발하여, 반시계방향으로 남쪽으로 30m, 동쪽으로 60m, 남쪽으로 20m, 동쪽으로 100m, 북쪽으로 50m, 서쪽으로 160m 이동하면 다시 출발점으로 되돌아가게 된다.

위 그림의 참외밭  면적은 6800m2이다. 만약 1m2의 넓이에 자라는 참외의 개수가 7이라면, 이 밭에서 자라는 참외의 개수는 47600으로 계산된다.

1m2의 넓이에 자라는 참외의 개수와, 참외밭을 이루는 육각형의 임의의 한 꼭짓점에서 출발하여 반시계방향으로 둘레를 돌면서 지나는 변의 방향과 길이가 순서대로 주어진다. 이 참외밭에서 자라는 참외의 수를 구하는 프로그램을 작성하시오.

 

 

입력

첫 번째 줄에 1m2의 넓이에 자라는 참외의 개수를 나타내는 양의 정수 K (1 ≤ K ≤ 20)가 주어진다. 참외밭을 나타내는 육각형의 임의의 한 꼭짓점에서 출발하여 반시계방향으로 둘레를 돌면서 지나는 변의 방향과 길이 (1 이상 500 이하의 정수) 가 둘째 줄부터 일곱 번째 줄까지 한 줄에 하나씩 순서대로 주어진다. 변의 방향에서 동쪽은 1, 서쪽은 2, 남쪽은 3, 북쪽은 4로 나타낸다.

 

 

출력

첫째 줄에 입력으로 주어진 밭에서 자라는 참외의 수를 출력한다.

 

 

 


 

문제 해결

문제에서 구하려는 도형의 넓이는 도형을 직사각형이라고 가정한 넓이에서 움푹 파인 넓이를 빼면 됩니다.

 

변의 입력은 가로, 세로가 번갈아가며 주어지므로 현재 변과 다음 변을 곱한 값 중 최대값을 maxArea에 저장합니다. 최대값이 갱신될 때마다 현재 변으로부터 "3번째 변과 4번째 변의 곱"을 maxArea에서 뺀 값을 res에 저장합니다. 입력되는 도형 구조 상 최대값을 나타내는 변으로부터 3번째 변과 4번째 변이 무조건 움푹 파인 부분이 되기 때문입니다.

 

 

 

코드

#include <iostream>

using namespace std;

pair<int, int> ary[6];
int n, maxArea = 1, cur, res;

int main(){
    
    cin >> n;

    for (int i = 0; i < 6; i++)
        cin >> ary[i].first >> ary[i].second;

    for (int i = 0; i < 6; i++){
        cur = ary[i].second * ary[(i + 1) % 6].second;

        if (cur > maxArea){
            maxArea = cur;
            res = maxArea - ary[(i + 3) % 6].second * ary[(i + 4) % 6].second;
        }
    }

    cout << res * n;
}

'🎲 BOJ > 🥈' 카테고리의 다른 글

[C++] 백준 2056 : 작업  (0) 2022.02.10
[C++] 백준 10826 : 피보나치 수 4  (0) 2022.02.06
[C++] 백준 1181 : 단어 정렬  (0) 2022.02.04
[C++] 백준 9084 : 동전  (0) 2022.02.03

 

 

문제

준원이는 저번 주에 살면서 처음으로 코스트코를 가 봤다. 정말 멋졌다. 그런데, 몇 개 담지도 않았는데 수상하게 높은 금액이 나오는 것이다! 준원이는 영수증을 보면서 정확하게 계산된 것이 맞는지 확인해보려 한다.

영수증에 적힌,

  • 구매한 각 물건의 가격과 개수
  • 구매한 물건들의 총 금액

을 보고, 구매한 물건의 가격과 개수로 계산한 총 금액이 영수증에 적힌 총 금액과 일치하는지 검사해보자.

 

 

입력

첫째 줄에는 영수증에 적힌 총 금액 가 주어진다.

둘째 줄에는 영수증에 적힌 구매한 물건의 종류의 수 이 주어진다.

이후 개의 줄에는 각 물건의 가격 와 개수 가 공백을 사이에 두고 주어진다.

 

 

출력

 

구매한 물건의 가격과 개수로 계산한 총 금액이 영수증에 적힌 총 금액과 일치하면 Yes를 출력한다. 일치하지 않는다면 No를 출력한다.

 

 


 

코드

 

#include <iostream>

using namespace std;

int total, n, price, m;

int main() {

	cin >> total >> n;

	for (int i = 0; i < n; i++) {
		cin >> price >> m;
		total -= price * m;
	}

	if (!total) cout << "Yes";
	else cout << "No";
}

 

'🎲 BOJ > 🥉' 카테고리의 다른 글

[C++] 백준 10824 : 네 수  (0) 2022.08.08
[C++] 백준 13305 : 주유소  (0) 2022.01.27


소원 빌고 왔다

+ Recent posts