문자열로 입력 받아서 덧셈을 하는 코드를 짠다. 주의사항은 아래와 같다. - 양수에는 부호가 없지만, 음수에는 - 부호가 있다. - 부호가 같으면 덧셈, 부호가 다르면 뺄셈을 한다. - 0은 항등원이므로 입력값에 0이 포함되는 경우에는 연산을 할 필요가 없다.
일단 양수, 0에는 부호가 없으므로 이런 숫자가 입력으로 들어오면 앞에 +를 붙여준다.
덧셈은 각 자리를 합한 뒤 10이 넘으면 다음 자리에 +1을 하고, 현재 자리에 10을 빼기만 하면 된다. 뺄셈은 계산 결과에 따라 추가적으로 처리해야 할 것들이 있다.내 경우에는 아래와 같은 순서로 진행하였다. 1. 음수인 배열의 각 자리에 -1을 곱한다. 2. A와 B의 각 자리를 합한다. 3. 합한 결과의 맨 앞이 0인 경우 0이 아닌 수가 나올 때까지 제거한다. 4. 맨 앞의 수가 0보다 작은 경우 부호를 -로 하고 각 자리에 -1을 곱한다. 아닌 경우에는 부호를 +로 한다. 5. 일의 자리부터 시작하여 0보다 작은 경우 앞의 자리 수를 1 빼고, 현재 자리 수에 +10을 한다. 6. 조정 후 3.의 처리를 추가로 진행한다.
마지막으로 결과 출력이 char로 이루어지므로 각 자리에 '0'을 더해줘 정상적으로 출력될 수 있게 하고, 부호가 +일 경우 이를 제거해준다.
2019. 11. 05 - 0에 대한 예외처리 추가 기존: 값이 0일 때도 연산 진행 변경: 입력 값에 0이 포함되는 경우 다른 값을 반환
2019. 10. 21 - 앞에 위치한 0 제거 코드 수정 기존: 맨 앞이 0인지 확인하여 erase. 0의 개수만큼 erase 함수 반복. 변경: 맨 앞이 0일 경우 연속으로 0이 나오는 수량을 확인하여 범위 삭제. erase 함수는 1회만 실행하는 대신 연속으로 확인하는 과정에서 for문이 돌아감
풀이 코드
#include <iostream>
using namespace std;
void BAEKJOON_15740()
{
string A;
string B;
cin >> A >> B;
// 입력 값이 0인 경우에 대한 예외처리
if (A == "0")
{
cout << A << endl;
}
else if (B == "0")
{
cout << B << endl;
}
// 음수가 아닌 경우 앞에 부호 추가
if (A[0] != '-')
{
A.insert(A.begin(), '+');
}
if (B[0] != '-')
{
B.insert(B.begin(), '+');
}
// 두 수의 합이 0인 경우
if (A[0] != B[0] && A.length() == B.length())
{
bool check = true;
for (size_t i = 1; i < A.length() && check; i++)
{
if (A[i] != B[i])
{
check = false;
break;
}
}
if (check)
{
cout << 0 << endl;
return;
}
}
// A가 긴 문자열, B가 짧은 문자열
if (A.length() < B.length())
{
A.swap(B);
}
A.resize(A.length(), 0);
// char to int
for (size_t i = 1; i < A.length(); i++)
{
A[i] -= '0';
}
for (size_t i = 1; i < B.length(); i++)
{
B[i] -= '0';
}
// 둘의 부호가 같은 경우
if (A[0] == B[0])
{
// 각 자리 별 계산
size_t gap = A.length() - B.length();
for (size_t i = 1; i < B.length(); i++)
{
A[gap + i] += B[i];
}
for (int i = A.length() - 1; i >= 2; i--)
{
if (A[i] >= 10)
{
A[i - 1]++;
A[i] -= 10;
}
}
if (A[1] >= 10)
{
A[1] -= 10;
A.insert(A.begin() + 1, 1);
}
}
// 둘의 부호가 다른 경우
else
{
// 음수인 수의 각 자리에 -1 곱하기
if (A[0] == '-')
{
for (size_t i = 1; i < A.length(); i++)
{
A[i] *= -1;
}
}
else
{
for (size_t i = 1; i < B.length(); i++)
{
B[i] *= -1;
}
}
// 각 자리별 계산
size_t gap = A.length() - B.length();
for (size_t i = 1; i < B.length(); i++)
{
A[gap + i] += B[i];
}
// 계산 후 앞에 위치한 0 제거
if (A[1] == 0)
{
int zeroCount = 0;
for (int i = 1; A[i] == 0; i++)
{
zeroCount++;
}
A.erase(A.begin() + 1, A.begin() + zeroCount + 1);
}
// 부호에 따른 조정
if (A[1] < 0)
{
A[0] = '-';
for (size_t i = 1; i < A.length(); i++)
{
A[i] *= -1;
}
}
else
{
A[0] = '+';
}
// 각 자리 조정
for (int i = A.length() - 1; i >= 2; i--)
{
if (A[i] < 0)
{
A[i - 1]--;
A[i] += 10;
}
}
// 조정 후 0 제거
if (A[1] == 0)
{
int zeroCount = 0;
for (int i = 1; A[i] == 0; i++)
{
zeroCount++;
}
A.erase(A.begin() + 1, A.begin() + zeroCount + 1);
}
}
for (size_t i = 1; i < A.length(); i++)
{
A[i] += '0';
}
if (A[0] == '+')
{
A.erase(A.begin());
}
cout << A << endl;
return;
}
입력은 세 글자로 제한된다. A, B의 값이 1~9로 제한되기 때문. 문자열로 입력 받아서 [0], [2]에 있는 값끼리 합하면 된다. 단, 이렇게 입력 받은 경우에는 [0]과 [2]에 저장된건 아스키코드 값인 48~57이므로 계산을 할 때 각 문자에 '0'만큼의 값을 뺀 후 계산해야 한다.
문제와는 별개로 A, B의 입력 값이 10 이상인 경우에는 ,의 위치를 특정할 수 없으므로 데이터의 형식에 맞춰 int, char, int 순서로 입력 받아야 한다. int를 읽어들일 때 숫자가 아닌 데이터가 나올 경우 stream 읽는 것을 중단하기 때문.
풀이 코드
#include <iostream>
using namespace std;
void BAEKJOON_10953()
{
int N;
cin >> N;
for (int i = 0; i < N; i++)
{
char input[4];
cin >> input;
cout << input[0] + input[2] - ('0' * 2) << endl;
}
return 0;
}
You are given the following information, but you may prefer to do some research for yourself.
1 Jan 1900 was a Monday.
Thirty days has September, April, June and November. All the rest have thirty-one, Saving February alone, Which has twenty-eight, rain or shine. And on leap years, twenty-nine.
A leap year occurs on any year evenly divisible by 4, but not on a century unless it is divisible by 400.
How many Sundays fell on the first of the month during the twentieth century (1 Jan 1901 to 31 Dec 2000)?
1901년 1월 1일 ~ 2000년 12월 31일까지 매월 1일이 일요일인 달이 몇 개인지 세는 문제.
1900년 1월 1일은 월요일이며, 윤년 규칙은 기존과 동일하게 4년(윤년), 100년(평년), 400년(윤년)의 구분자를 갖는다.
* 윤년 규칙에 따라 1900년 2월은 평년으로 28일이다.
1. 계산을 시작하는 해의 1월 1일의 요일을 구한다.
* 시작하는 해의 1월 1일이 일요일인 경우 반환값에 이것이 누락되지 않도록 해야 한다.
2. 각 월에 해당하는 날짜만큼을 더한 후 요일을 구하여 일요일이면 반환값에 +1을 한다.
* 2월인 경우에는 % 4, % 100, % 400 에 대한 처리를 하여 요일을 구한다.
3. 구한 결과값을 반환한다.
int Problem019()
{
// 기준일자 1900년 1월 1일(월)
// 일 0, 월 1, 화 2, 수 3, 목 4, 금 5, 토 6
int REFERENCE_YEAR = 1900;
int startYear = 1901;
int endYear = 2000;
int day = 1;
// 시작년도에 맞게 세팅
for (int year = REFERENCE_YEAR; year < startYear; year++)
{
if (year % 400 == 0)
{
day += 366;
}
else if (year % 100 == 0)
{
day += 365;
}
else if (year % 4 == 0)
{
day += 366;
}
else
{
day += 365;
}
day %= 7;
}
int ret = (day == 0) ? 1 : 0;
// 계산하기
for(int year = startYear; year <= endYear; year++)
{
for (int month = 1; month <= 12; month++)
{
switch (month)
{
case 1:
case 3:
case 5:
case 7:
case 8:
case 10:
case 12:
day += 31;
break;
case 4:
case 6:
case 9:
case 11:
day += 30;
break;
case 2:
day += year % 4 ? 28 : 29;
day += year % 100 ? 0 : -1;
day += year % 400 ? 0 : 1;
break;
default:
assert(false);
}
day %= 7;
if (day == 0)
{
ret++;
}
}
}
return ret;
}
포도주 잔 n과 각 잔에 들어있는 포도주의 양이 주어질 때 최대로 마실 수 있는 포도주의 양을 출력한다. 단, 연속으로 놓여 있는 세 잔을 모두 마실 수는 없다.
테스트 케이스
6 6 10 13 9 8 1
33
6 8 2 0 0 2 8
20
문제 풀이
계단 오르기 문제와 비슷하지만 건너 뛰는 간격에 대한 제한이 없다는 차이가 있다. 즉, 2칸을 건너뛰지 않고 3칸을 건너뛸 수도 있다는 것. 이 때문에 점화식을 만든 후 값을 구하는 것은 계단오르기와 동일하나 dp[i - 2]와 dp[i-3]만 알면 되었던 계단오르기와 달리, dp[i - 3] 대신 dp[0] ~ dp[i - 3] 중에서 가장 큰 값을 알아야 한다. dp 중에서 가장 큰 값을 저장하는 변수를 만들고 새로운 dp 값을 구할 때마다 이 변수에 가장 큰 값을 입력해두는 식으로 진행하면 최대로 마실 수 있는 포도주의 양을 구할 수 있다.
풀이 코드
#include <iostream>
using namespace std;
void BAEKJOON_2156()
{
int n;
cin >> n;
uint32_t max;
if (n == 1)
{
cin >> max;
}
else
{
/*----------배열 할당 및 값 입력-----*/
uint32_t* pt = new uint32_t[n + 1];
uint32_t* dp = new uint32_t[n + 1];
pt[0] = 0;
for (int i = 1; i <= n; i++)
{
cin >> pt[i];
}
/*---------점화식-------------------*/
dp[0] = 0;
dp[1] = pt[1];
dp[2] = pt[1] + pt[2];
max = dp[2] > dp[1] ? dp[2] : dp[1];
uint32_t semiMax = 0;
/*---------값 구하기----------------*/
for (int i = 3; i <= n; i++)
{
semiMax = dp[i - 3] > semiMax ? dp[i - 3] : semiMax;
uint32_t before = dp[i - 2] + pt[i];
uint32_t other = semiMax + pt[i - 1] + pt[i];
dp[i] = before > other ? before : other;
if (dp[i] > max)
{
max = dp[i];
}
}
/*----------배열 할당 해제----------*/
delete[] pt;
delete[] dp;
}
cout << max << endl;
return;
}
아래 세 가지 규칙을 바탁으로 X를 1로 만드는데 필요한 최소한의 연산 횟수를 출력한다. 1. X가 3으로 나누어 떨어지면, 3으로 나눈다. 2. X가 2로 나누어 떨어지면, 2로 나눈다. 3. 1을 뺀다.
테스트 케이스
2
1
10
3
10000
14
문제 풀이
일정 범위까지 점화식을 만들고 점화식을 바탕으로 아래의 내용에 대해 판단한다. 1. m1, m2, m3 변수를 만들고 100만보다 큰 수로 초기화 한다. 2. n % 3 == 0인 경우 [n / 3]의 값을 구해 m1에 저장한다. 3. n % 2 == 0인 경우 [n / 2]의 값을 구해 m2에 저장한다. 4. [n - 1]의 값을 구해 m3에 저장한다. 5. m1, m2, m3의 값을 비교해 가장 작은 값 + 1을 [n]에 저장한다. 6. 1~5를 반복한다.
풀이 코드
#include <iostream>
using namespace std;
void BAEKJOON_1463()
{
int N;
cin >> N;
int* count = new int[N + 1];
count[0] = 0;
count[1] = 0;
for (int i = 2; i <= N; i++)
{
int d3 = 1000001;
int d2 = 1000001;
int m1 = 1000001;
if (i % 3 == 0)
{
d3 = 1 + count[i / 3];
}
if (i % 2 == 0)
{
d2 = 1 + count[i / 2];
}
m1 = 1 + count[i - 1];
count[i] = d3 < d2 ? d3 : d2;
count[i] = count[i] < m1 ? count[i] : m1;
}
cout << count[N] << endl;
delete[] count;
return;
}