백준 No.10757 [큰 수 A+B]
본문 바로가기
Algorithm (C++ based)/BOJ

백준 No.10757 [큰 수 A+B]

by 조훈이 2021. 1. 5.

// Baekjoon Online Judge No.10757 [큰 수 A+B]


   Code   

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
#include <iostream>
#include <string>
#include <vector>
 
using namespace std;
 
int main() {
    string A, B;
    bool AisLonger = false;
    bool BisLonger = true;
 
    cin >> A;
    cin >> B;
 
    int maxLen = B.length();
    int minLen = A.length();
 
    if (A.length() > B.length()) {
        maxLen = A.length();
        minLen = B.length();
        AisLonger = true;
        BisLonger = false;
    }
 
    vector<int> sum;
    
    int olim = 0;
 
    for (int i = 1; i <= maxLen; i++) {
        if (i <= minLen) {
            sum.push_back((A[A.length() - i] + B[B.length() - i] - 96 + olim) % 10);
            olim = (A[A.length() - i] + B[B.length() - i] - 96 + olim) / 10;
        }
        else if (AisLonger) {
            sum.push_back((A[A.length() - i] - 48 + olim) % 10);
            olim = (A[A.length() - i] - 48 + olim) / 10;
        }
        else { // B is longer than A
            sum.push_back((B[B.length() - i] - 48 + olim) % 10);
            olim = (B[B.length() - i] - 48 + olim) / 10;
        }
 
        if (i == maxLen) {
            if (olim) sum.push_back(olim);
        }
    }
 
    for (int i = sum.size() - 1; i >= 0; i--) {
        cout << sum[i];
    }
}
cs

 


   시행착오   

  이 문제에서 눈여겨보아야 할 것은 입력조건이다. A와 B의 값이 10^10,000 미만인 값까지 입력이 가능해야 하는데, 자료형중 가장 큰 수를 표현할 수 있는 자료형인 double 조차도 약 1.7 * 10^308 까지밖에 표현을 하지 못한다.

    이는 C++에서 덧셈에 대한 새로운 시각을 요구하는 문제였다. 단순하게 생각해서 overflow가 되는 횟수를 count해서 풀어야하나? 라는 생각을 했지만 이내 접었다.

  첫번째로 생각한 방법은 int형 vector를 선언하여 input되는 한자리 한자리 수를 vector에 넣는 것 이었다. 실제로 가능한 방법이긴 하지만 수의 길이만큼 vector에 하나하나 push_back을 해 주어야 하기 때문에 효율적이지 못할 것이라고 생각하였다. 만약 수의 크기가 10^10,000에 육박하는 크기라면 많은 시간이 걸릴 것이기 때문이다. 또한 A와 B를 더해야 하니 시간이 더 소요가 될 거라고 생각을 했다. 그래서 생각해낸 방식이 input 문자열로 받는 것이었다.

 

   How to solve   

  두 개의 input을 string의 형태로 받고, vector<int> sum에 첫 번째 자리 수부터 더해진 값이 push_back되어 실제 덧셈이 되는 과정처럼 덧셈을 진행하는 코드를 구현하였다.


12
13
    cin >> A;
    cin >> B;
cs

  A와 B를 string형태로 입력받는다.

 

15
16
    int maxLen = B.length();
    int minLen = A.length();
cs

  우선 default 값으로 A, B중 더 긴 문자열을 B라고 둔다. 또한 이에 따라 B의 길이값으로 maxLen변수를 정의하였다.  minLen은 A의 길이값이 되었다. 추후 A가 더 길면 maxLen에 A의 길이값, minLen에 B의 길이값을 넣으면 되기 때문이다. B가 더 길다고 우선 가정했기에 AisLonger변수는 false, BisLonger변수는 true로 정의한다.

 

18
19
20
21
22
23
   if (A.length() > B.length()) {
        maxLen = A.length();
        minLen = B.length();
        AisLonger = true;
        BisLonger = false;
    }
cs

  15 ~ 16번째 line에서 B의 길이가 더 길다고 가정하고 값을 부여하였었다.

  18 ~ 23번째 line에선 A의 길이가 더 길 경우 maxLenminLen의 값을 다시 정의하고,

AisLonger = true, BisLonger = false 로 재정의 한다.

  B가 더 길거나 A의 길이와 B의 길이가 같을 경우엔 그냥 전에 정의한 대로 둔다.

 

25
26
27
    vector<int> sum;
    
    int olim = 0;
cs

  25번째 line에선 결과값을 넣을 int형 vector를 선언하였다.

  27번째 line에선 덧셈 과정에서 발생할 올림수의 기능을 하는 변수를 선언하였다.

 

29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
    for (int i = 1; i <= maxLen; i++) {
        if (i <= minLen) {
            sum.push_back((A[A.length() - i] + B[B.length() - i] - 96 + olim) % 10);
            olim = (A[A.length() - i] + B[B.length() - i] - 96 + olim) / 10;
        }
        else if (AisLonger) {
            sum.push_back((A[A.length() - i] - 48 + olim) % 10);
            olim = (A[A.length() - i] - 48 + olim) / 10;
        }
        else { // B is longer than A
            sum.push_back((B[B.length() - i] - 48 + olim) % 10);
            olim = (B[B.length() - i] - 48 + olim) / 10;
        }
 
        if (i == maxLen) {
            if (olim) sum.push_back(olim);
        }
   }
cs

  문제 풀이에 가장 핵심이 되는 부분이다. A, B 의 첫번째 자리 수는 A[0], B[0]이 아닌 A와 B의 마지막 글자의 값이라 for문을 i = 1부터 돌리면서 A[A.length() - i], B[B.length() - i]를 이용하여 연산을 진행하였다.

  고려해야 할 요소들은 다음과 같다.

  • (a) : 덧셈 과정에서 발생하는 올림수
  • (b) : 두 수의 덧셈이 이루어지는 곳
  • (c) : 짧은 수의 덧셈이 끝난 경우.

  첫번째로, (a) 의 경우는 말 그대로 올림수에 대한 부분이다. for 문이 한자리 한자리 숫자를 더해가면서 이전 자리 수의 덧셈에서 발생한 올림수도 더해준다.

  두번째로, (b) 의 경우는 더해야 할 요소가 세 가지가 있다. A의 숫자, B의 숫자, 그리고 올림수이다. 이 경우에 대한 조건식은 30번째 line이다. 코드를 보면 더해지는 숫자들에 -96, -48을 한 것을 볼 수 있는데 이는 처음에 입력을 string의 형태로 받았으므로 A[k], B[k]의 자료형은 char 이기에 char형태인 '0', '1' ... 의 ASCII코드 10진수 값이 48, 49 ... 임을 고려하여 넣은 뻴셈이다.

  세번째로, (c) 의 경우는 짧은 수의 덧셈은 다 마무리가 되고 남아있는 긴 수와 올림수만 더해주면 된다. 34, 38번째 조건문에서 (c)의 과정을 수행한다. 34번째는 A가 B보다 길 경우, 38번째는 B가 A보다 길 경우이다.

  sum vectorpush_back 되는 값은 한 자리 숫자여야만 한다. 다 더해진 값이 19라면 sum vector엔 첫째자리수인 9만 push_back되고 십의자리수인 1은 올림수로 다음 자리 수의 덧셈에 전달된다. 따라서 다 더한 값에 '% 10'을 해 준것을 볼 수 있다. olim은 당연히 '/ 10'을 해 주었다.

 

  43번째 line에선 i == maxLen 일 경우 즉, 긴 수의 끝까지 덧셈을 실행했을때의 경우이다. 이 경우를 따로 빼놓은 이유는 마지막 자리의 덧셈에서 또 올림수가 발생했다면 sum 에 그 올림수까지 push_back을 해주어야 하기 때문이다.

 

48
49
50
    for (int i = sum.size() - 1; i >= 0; i--) {
        cout << sum[i];
    }
 
cs

  A와 B의 덧셈에 대한 결과를 첫째자리수부터 push_back 했으므로 출력할땐 sum[0]부터가 아닌 sum[sum.size() - 1]부터 출력해야 한다. 따라서 for문의 범위가 이와 같다.

728x90

'Algorithm (C++ based) > BOJ' 카테고리의 다른 글

백준 No.2603 [색종이 만들기]  (0) 2021.01.24
백준 No.2447 [별 찍기 - 10]  (0) 2021.01.24
백준 No.10844 [쉬운 계단 수]  (0) 2020.11.18
백준 No.1932 [정수 삼각형]  (0) 2020.11.16
백준 No.1149 [RGB거리]  (0) 2020.11.10

댓글