천천히 빛나는

백준 단계 8 : 일반 수학 1 (C++) 본문

C++/BAEKJOON (C++)

백준 단계 8 : 일반 수학 1 (C++)

까만콩 •ᴥ• 2023. 9. 7. 00:57

2745. B진법 수 N이 주어진다. 이 수를 10진법으로 바꿔 출력하는 프로그램을 작성하시오. 10진법을 넘어가는 진법은 숫자로 표시할 수 없는 자리가 있다. 이런 경우에는 다음과 같이 알파벳 대문자를 사용한다.

#include <iostream>
#include <cmath>
using namespace std;
int main() {
	ios::sync_with_stdio(false);
	cin.tie(0);
	string N;
	int B;
	int dec = 0;
	cin >> N >> B;
	for (int i = 0; i < N.length(); i++)
	{
		int temp;
		if ((N[N.length() - i - 1] >= 'A') && (N[N.length() - i - 1] <= 'Z')) {
			temp = (N[N.length() - i - 1] - 'A') + 10;
		}
		else {
			temp = N[N.length() - i - 1] - '0';
		}
		dec += temp * pow(B, i);
	}

	cout << dec;
	return 0;
}

진법 변환에 대한 수학적인 지식이 있다면 쉽게 풀 수 있는 문제이다.

 

 

 

11005. 10진법 수 N이 주어진다. 이 수를 B진법으로 바꿔 출력하는 프로그램을 작성하시오. 10진법을 넘어가는 진법은 숫자로 표시할 수 없는 자리가 있다. 이런 경우에는 다음과 같이 알파벳 대문자를 사용한다. A: 10, B: 11, ..., F: 15, ..., Y: 34, Z: 35

#include <iostream>
#include <algorithm>
#include <string>
using namespace std;
int main() {
	ios::sync_with_stdio(false);
	cin.tie(0);
	int N;
	int B;
	cin >> N >> B;
	string change ="";
	while (N != 0) {
		if (N % B >= 10) {
			change += char(N % B) - char(10) + 'A';
			//change += char(N % B) - '10' + 'A' << endl;
		}
		else {
			change += to_string(N % B);
		}
		N /= B;
	}
	reverse(change.begin(), change.end());
    cout << change;
	return 0;
}

그동안 char형 숫자를 int 형으로 바꾸는 방법(숫자는 '0'을 뺀다와 같은 방법)을 사용하다 숫자를 char형으로 바꾸는 부분에서 헷갈려서 잠시 헤맸다.

 

보라색이 실제 문자이고 아스키코드가 80, 81과 같은 숫자가 된다. '4'를 예로 들면, 84에서 '0', 즉 80을 빼게 되면 4가 되기 때문에 int로 변환하면 바로 4가 된다

반대로, 10와 같은 int형 숫자가 'A'가 되기 위해서는, 아스키코드 'A'에 0을 더해준 값이 되면 된다. 즉 10에서 10을 빼고 그 값을 더하면, 'A'의 아스키코드 97이 그대로 되므로, 이것을 char로 표현하면 'A'가 되는 것이다.

나는 char(숫자) - char(숫자)로 했는데, 이건 사실 아스키코드 5 에서 아스키코드 1을 빼는 것과 마찬가지라서 char(숫자 - 숫자)이랑 똑같은 값이 된다.

이와 같은 원리를 이해했다면 쉽게 풀 수 있었을 것이다.

 

 

 

2720. 미국으로 유학간 동혁이는 세탁소를 운영하고 있다. 동혁이는 최근에 아르바이트로 고등학생 리암을 채용했다. 동혁이는 리암에게 실망했다. 리암은 거스름돈을 주는 것을 자꾸 실수한다. 심지어 $0.5달러를 줘야하는 경우에 거스름돈으로 $5달러를 주는것이다!  거스름돈의 액수가 주어지면 리암이 줘야할 쿼터(Quarter, $0.25)의 개수, 다임(Dime, $0.10)의 개수, 니켈(Nickel, $0.05)의 개수, 페니(Penny, $0.01)의 개수를 구하는 프로그램을 작성하시오. 거스름돈은 항상 $5.00 이하이고, 손님이 받는 동전의 개수를 최소로 하려고 한다. 예를 들어, $1.24를 거슬러 주어야 한다면, 손님은 4쿼터, 2다임, 0니켈, 4페니를 받게 된다.

#include <iostream>
#include <algorithm>
#include <string>
using namespace std;
int main() {
	ios::sync_with_stdio(false);
	cin.tie(0);
	int t, money, quarter, dime, nickel, penny;
	cin >> t;
	for (int i = 0; i < t; i++)
	{
		cin >> money;
		quarter = money / 25;
		money -= quarter * 25;
		cout << quarter << " ";
		dime = money / 10;
		money -= dime * 10;
		cout << dime << " ";
		nickel = money / 5;
		money -= nickel * 5;
		cout << nickel << " ";
		penny = money;
		money -= penny;
		cout << penny << "\n";
	}
	return 0;
}

이 문제도 간단하게 풀 수 있는 문제이다.

 

 

 

2043. 상근이는 친구들과 함께 SF영화를 찍으려고 한다. 이 영화는 외계 지형이 필요하다. 실제로 우주선을 타고 외계 행성에 가서 촬영을 할 수 없기 때문에, 컴퓨터 그래픽으로 CG처리를 하려고 한다. 외계 지형은 중앙 이동 알고리즘을 이용해서 만들려고 한다. 상근이는 어떤 점은 한 개 보다 많은 정사각형에 포함될 수 있다는 사실을 알았다. 메모리 소모량을 줄이기 위해서 중복하는 점을 한 번만 저장하려고 한다. 과정을 N번 거친 후 점 몇 개를 저장해야 하는지 구하는 프로그램을 작성하시오.

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

int main() {
    int n, dot = 2;
    cin >> n;
    // 4 9 25 81
    // 2^2 3^2 5^2 9^2
    for (int i = 0; i < n; i++)
    {
        dot = dot * 2 - 1;
    }    
    cout << int(pow(dot, 2));
    return 0;
}

pow가 double형 반환이라 int로 변환해서 출력 안하면 틀렸다고 뜬다.

 

 

 

2292. 위의 그림과 같이 육각형으로 이루어진 벌집이 있다. 그림에서 보는 바와 같이 중앙의 방 1부터 시작해서 이웃하는 방에 돌아가면서 1씩 증가하는 번호를 주소로 매길 수 있다. 숫자 N이 주어졌을 때, 벌집의 중앙 1에서 N번 방까지 최소 개수의 방을 지나서 갈 때 몇 개의 방을 지나가는지(시작과 끝을 포함하여)를 계산하는 프로그램을 작성하시오. 예를 들면, 13까지는 3개, 58까지는 5개를 지난다.

#include<iostream>
using namespace std;
int main() {
    int n, room = 1;
    int min = 2, max = 7;
    cin >> n;
    while (n > 1) {
        if ((min <= n) && (n <= max)) {
            room++;
            break;
        }
        min = max + 1;
        max += 6 * (room + 1);
        room++;
    }
    cout << room;
    return 0;
}

2 ~ 7 / 8 ~ 19 / 20 ~ 37 / 38 ~ 61과 같이 최소 개수의 방을 나눌 수 있다.

방을 이동할 때마다 max 값이 6 * (room+1)가 되는 것을 이용하였다.

 

 

 

1193. 무한히 큰 배열에 다음과 같이 분수들이 적혀있다. 이와 같이 나열된 분수들을 1/1 → 1/2 → 2/1 → 3/1 → 2/2 → … 과 같은 지그재그 순서로 차례대로 1번, 2번, 3번, 4번, 5번, … 분수라고 하자. X가 주어졌을 때, X번째 분수를 구하는 프로그램을 작성하시오.

#include<iostream>
using namespace std;
int main() {
    int x;
    cin >> x;
    int n = 2, count = 1, deno = 1, mole = 1;
    while (count != x) {
        if (n % 2 == 0) {
            deno = n;
            mole = 1;
            for (int i = 0; i < n; i++)
            {
                count++;
                if (count == x) {
                    break;
                }
                deno--;
                mole++;
            }
            
        }
        else {
            deno = 1;
            mole = n;
            for (int i = 0; i < n; i++)
            {
                count++;
                if (count == x) {
                    break;
                }
                deno++;
                mole--;
            }
        }
        n++;
    }
    
    cout << mole << "/" <<deno;
    return 0;
}

나는 이중 for문을 이용해서 구현하였는데 다른 코드를 보니 이중 for문이 아니어도 깔끔하게 구현이 가능하였다.

 

#include<iostream>
using namespace std;
int main() {
    int x;
    cin >> x;
    int i = 1;
    while (x > i) {
        x -= i;
        i++;
    }
    if (x % 2 == 0) {
        cout << i - (x - 1) << "/" << x;
    }
    else {
        cout << x << "/" << i - (x - 1);
    }
    return 0;
}

i번째 대각선에는 i개의 수가 존재한다는 점을 이용해야 한다.

예를 들어 4번째 수인 1/3의 경우, 1보다 크다. 즉 1번째 줄을 벗어난다는 뜻이다. 그럼 1을 빼서 3으로 만든다. 3은 2보다 크므로 2번째에 있는 수를 벗어난다는 뜻이다. 2를 빼주게 된다. 그럼 1이 되고 3보다 작으므로 3번째 줄의 첫번째 숫자가 된다는 뜻이 된다. 

그다음 대각선 홀/짝에 따라 방향을 고려해서 분자 분모를 출력해주면 된다.

 

 

 

2869. 땅 위에 달팽이가 있다. 이 달팽이는 높이가 V미터인 나무 막대를 올라갈 것이다. 달팽이는 낮에 A미터 올라갈 수 있다. 하지만, 밤에 잠을 자는 동안 B미터 미끄러진다. 또, 정상에 올라간 후에는 미끄러지지 않는다. 달팽이가 나무 막대를 모두 올라가려면, 며칠이 걸리는지 구하는 프로그램을 작성하시오.

#include<iostream>
using namespace std;
int main() {
    int a, b, v;
    cin >> a >> b >> v;
    int day = 1;
    while (1) {
        v -= a;
        if (v <= 0)
            break;
        v += b;
        day++;
    }
    cout << day;
    return 0;
}

시간 초과가 떴다. 하루하루 계산하는 거 외에 다른 방법이 있다고 생각했다.

 

#include<iostream>
#include<cmath>
using namespace std;
int main() {
    double a, b, v;
    cin >> a >> b >> v;
    int day = 1 + ceil((v - a) / (a - b));
    cout << day;
    return 0;
}

하루동안 a-b만큼 올라갈 수 있다. 하지만 단순히 v / (a-b)하고 반올림을 해버리면 마지막날에 꼭대기까지 오르고, 굳이 미끄러진 후에 다시 오르는 상황이 발생한다. 이러한 상황을 없애기 위해 마지막 날은 무조건 a만큼 오른다고 생각하여 v에서 a를 빼준 후 1일을 따로 추가해주도록 했다.