[백준] 1단계. 입출력과 사칙연산

leeeha·2021년 6월 26일
0

백준

목록 보기
1/186
post-thumbnail

https://www.acmicpc.net/step/1

백준 1단계의 총 11문제 중에서 아주 기초적인 문제들을 제외하고, 나머지 6문제에 대한 풀이과정입니다.

10171번 고양이

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

#include <iostream>
using namespace std;

int main() {
	cout << "\\    /\\" << endl;
	cout << " )  ( \')" << endl;
	cout << "(  /  )" << endl;
	cout << " \\(__)|" << endl;

	return 0;
}

/*
	\    /\
	 )  ( ')
	(  /  )
	 \(__)|
*/

10172번 개

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

#include <iostream>
using namespace std;

int main() {
	cout << "|\\_/|" << endl;
	cout << "|q p|   /}" << endl;
	cout << "( 0 )\"\"\"\\" << endl;
	cout << "|\"^\"`    |" << endl;
	cout << "||_/=\\\\__|" << endl;

	return 0;
}

/*

|\_/|
|q p|   /}
( 0 )"""\
|"^"`    |
||_/=\\__|

*/
  • `(back quote)랑 /(forward slash)는 특수 문자가 아니므로 그대로 출력된다.
  • '(single quote), "(double quote), \(back slash)와 같은 특수 문자들은 앞에 백슬래쉬 붙여줘야 해당 문자 자체가 출력된다. 이처럼 백슬래쉬는 문자의 특수 기능을 없애는 역할을 한다.

1008번 A/B

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

  • 실제 정답과 출력값의 절대오차 또는 상대오차가 10^(-9) 이하면 정답이다?
    소수점 아래 자리수가 '9자리 이상'이면 된다!
  • precision 함수는 소수의 정수부, 소수부를 모두 포함해서 자릿수를 결정한다.
  • 이때 fixed를 사용하면, 정수부를 제외하고 '소수점 아래의 자릿수만' 지정할 수 있다.
#include <iostream>
using namespace std;

int main()
{
    int a = 10;
    int b = 3;

    cout << fixed;
    cout.precision(9);
    cout << a / (double)b << endl;
    // 3.333333333 (소수점 아래부터 9자리)

    cout.unsetf(ios::fixed);
    cout << a / (double)b;
    // 3.33333333 (정수부, 소수부 모두 포함해서 9자리)
}

1008번 답 (아래 코드는 소수점 아래 9자리까지만 출력했지만, 자릿수를 더 늘려도 된다.)

#include <iostream>
using namespace std;

int main()
{
    int a, b;
    cin >> a >> b;

	// C++의 iostream 스타일
    cout << fixed;
    cout.precision(9);
    cout << a / (double)b << endl;

	// C의 stdio.h 스타일
    printf("%.9lf\n", a / (double)b);

    return 0;
}

✋ 잠깐, 분모가 0일 때는? 무한대를 뜻하는 inf(infinite)가 출력된다.


10869번 사칙연산

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

#include <iostream>
using namespace std;

int main()
{
    int a, b;
    cin >> a >> b;

    cout << a + b << endl;
    cout << a - b << endl;
    cout << a * b << endl;
    cout << a / b << endl; // 몫 (a,b 모두 int형이므로 소수점 버림)
    cout << a % b << endl; // 나머지


    return 0;
}

10430번 나머지(modulo) 연산

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

(A+B)%C는 ((A%C) + (B%C))%C 와 같을까?
(A×B)%C는 ((A%C) × (B%C))%C 와 같을까?
세 수 A, B, C가 주어졌을 때, 위의 네 가지 값을 구하는 프로그램을 작성하시오.

#include <iostream>
using namespace std;

int main()
{
    int A, B, C;
    cin >> A >> B >> C; // 5 8 4

    cout << (A + B) % C << endl; // 13 % 4 == 1
    cout << ((A % C) + (B % C)) % C << endl; // 1 % 4 == 1
    cout << (A * B) % C << endl; // 40 % 4 == 0
    cout << ((A % C) * (B % C)) % C << endl; // 0 % 4 == 0

    return 0;
}

✋ 잠깐, 결과 확인만 하지 말고 아래의 등식들이 왜 성립하는지 간단하게 증명해보자!

  • (A+B)%C == ((A%C) + (B%C))%C
  • (A*B)%C == ((A%C) * (B%C))%C
    아래 사진처럼 나머지 연산 해보면 당연한 결과인데, 눈으로만 봤을 때는 왜 그런지 이해가 안 될 수 있다!

출처: https://st-lab.tistory.com/214

iostream은 입/출력을 수행하기 위한 모든 C++ 스트림들을 포함한 헤더파일이다.
printf는 cout보다 빠르기 때문에 특수한 상황에서 주로 쓰이고, 보통 C++에서는 cout을 쓴다. 이는 <cstdio>와 <iostream>은 하는 일이 같지만, 둘 다 사용할 수 있다면 여러모로 iostream을 사용하는 것이 더 안전하기 때문인데, 자세한 이유는 다음과 같다.

  • type-safe : iostream은 %d, %f와 같은 서식 지정자 없이, 바로 변수명을 사용하기 때문에 컴파일러가 정적으로(static) 객체 타입을 파악할 수 있다.
    그러나, cstdio는 변수값을 %d, %f와 같은 서식 지정자에 넘겨주는 방식이기 때문에, 입/출력하는 변수가 어떤 타입인지 컴파일러는 알 수 없으며, 런타임에 동적(dynamic)으로만 알 수 있다. 따라서 iostream이 더 type-safe하다.
  • 에러 : cstdio는 입/출력할 객체의 타입이 반드시 서식 지정자와 일치해야 하는데, iostream은 그렇지 않다. 그래서 iostream이 error 발생 가능성이 더 적다.
  • 확장성 : iostream은 기존 코드를 바꾸지 않고, 사용자가 정의한 타입을 입/출력할 수 있다.
  • 상속성 : iostream 메커니즘은 std::ostream이나 std:istream같은 real class로부터 만들어지기 때문에, cstdio의 FILE*과는 달리 상속이 가능하다. 따라서 사용자가 직접 stream을 정의해서 작동시킬 수 있다. cstdio의 printf 함수는 인자의 type을 검사하지 않는 가변 인자 함수이고, 다른 type으로 overload 될 수도 없다.

2588번 곱셈

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

6번은 입력 받은 두 정수를 그냥 곱하면 되고, 3, 4, 5번은 두 번째 정수를 자릿수에 따라 분리해서 첫번째 정수와 각각 곱해줘야 한다. 그렇다면, 세 자리 정수를 한 자리씩 분리하려면 어떻게 해야 할까?

방법 1: 나눗셈 연산 (몫, 나머지)
방법2: 문자 배열, atoi 함수 이용
방법3: string, stoi 함수 이용


방법1. 나눗셈 연산

#include <iostream>
using namespace std;

int main() {
	int a, b;
	cin >> a >> b;

	cout << a * (b % 10) << "\n";
	cout << a * ((b % 100) / 10) << "\n";
	cout << a * (b / 100) << "\n";
	cout << a * b << "\n";

	return 0;
}

✋ 잠깐, 줄바꿈을 위해 사용되는 std::endl과 '\n'의 차이점은 무엇일까?

출처: https://cocoon1787.tistory.com/135

// MANIPULATORS
template <class _Elem, class _Traits>
basic_ostream<_Elem, _Traits>& __CLRCALL_OR_CDECL endl(
    basic_ostream<_Elem, _Traits>& _Ostr) { // insert newline and flush stream
    _Ostr.put(_Ostr.widen('\n'));
    _Ostr.flush();
    return _Ostr;
}

endl은 newline뿐만 아니라 출력 버퍼를 비우는 flush 함수도 항상 같이 실행되기 때문에, "\n"만 출력 하는 것보다 시간이 오래 걸린다. 아래는 실제 테스트 결과이다.

#include<iostream>
#include<time.h>
using namespace std;

int main()
{
	clock_t start, end; // clock_t는 long형 4바이트
	long time1, time2, time3;

	// cout, endl
	start = clock();
	for (int i = 0; i < 1000; i++)
		cout << i << endl;
	end = clock();
	time1 = end - start;

	// cout , \n
	start = clock();
	for (int i = 0; i < 1000; i++)
		cout << i << "\n";
	end = clock();
	time2 = end - start;

	// printf, \n
	start = clock();
	for (int i = 0; i < 1000; i++)
		printf("%d\n", i);
	end = clock();
	time3 = end - start;

	printf("\n\n");

	// 출력하는 데 걸린 시간 비교
	cout << "cout << i << endl : " << time1 << "ms" << endl;
	cout << "cout << i << \"\\n\" : " << time2 << "ms" << endl;
	cout << "printf(\"%d\\n\", i) : " << time3 << "ms" << endl;

	return 0;
}

🤔 근데, flush 함수가 '출력 버퍼를 비운다'는 게 무슨 뜻일까?

참고 링크: https://yechoi.tistory.com/48


방법2. 문자 배열, atoi 함수 이용

  • 세 자리 정수를 문자 배열로 입력 받으려면, 마지막 널문자까지 포함해서 4바이트가 필요하다.
  • 문자는 내부적으로 아스키코드에 따라 정수로 변환되는데, 문자 '0'은 십진수 48에 해당한다.
  • atoi 함수는 문자열을 정수로 변환한다. (실패하면 0을 리턴)
    int atoi(char const* String);
#include <iostream>
using namespace std;

int main() {
	int a;
	char b[4];
	cin >> a >> b;

	cout << a * (b[2] - 48) << "\n"; // 일의 자리수
	cout << a * (b[1] - 48) << "\n"; // 십의 자리수
	cout << a * (b[0] - 48) << "\n"; // 백의 자리수
	cout << a * atoi(b) << "\n"; // 문자 배열을 정수로 변환해주는 atoi 함수

	return 0;
} 

방법3. string, stoi 함수 이용

#include <iostream>
#include <string>
using namespace std;

int main() {
	int a;
	string b;
	cin >> a >> b;

	cout << a * (b[2] - 48) << "\n"; // 일의 자리수
	cout << a * (b[1] - 48) << "\n"; // 십의 자리수
	cout << a * (b[0] - 48) << "\n"; // 백의 자리수
	cout << a * stoi(b) << "\n"; // 문자열을 정수로 변환해주는 stoi 함수

	return 0;
} 
profile
습관이 될 때까지 📝

0개의 댓글